forked from blender/blender
main sync #3
@ -893,6 +893,23 @@ static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static std::optional<BL::BoolAttribute> 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,
|
||||
@ -983,16 +1000,22 @@ 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 false;
|
||||
};
|
||||
|
||||
/* create faces */
|
||||
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
|
||||
if (!subdivision) {
|
||||
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
|
||||
const int poly_index = t.polygon_index();
|
||||
const MPoly &b_poly = polys[poly_index];
|
||||
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();
|
||||
@ -1012,13 +1035,14 @@ static void create_mesh(Scene *scene,
|
||||
else {
|
||||
vector<int> vi;
|
||||
|
||||
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
|
||||
const MLoop *loops = static_cast<const MLoop *>(b_mesh.loops[0].ptr.data);
|
||||
|
||||
for (int i = 0; i < numfaces; i++) {
|
||||
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(i) || use_loop_normals;
|
||||
|
||||
vi.resize(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
|
||||
colliding_names = []
|
||||
for collection in (
|
||||
# Built-in names.
|
||||
{"shade_smooth": None, "crease": None},
|
||||
{"crease": None},
|
||||
mesh.attributes,
|
||||
None if ob is None else ob.vertex_groups,
|
||||
):
|
||||
|
@ -74,7 +74,7 @@ struct Scene;
|
||||
/* keep in sync with MFace/MPoly types */
|
||||
typedef struct DMFlagMat {
|
||||
short mat_nr;
|
||||
char flag;
|
||||
bool sharp;
|
||||
} DMFlagMat;
|
||||
|
||||
typedef enum DerivedMeshType {
|
||||
|
@ -453,12 +453,15 @@ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
|
||||
*
|
||||
* Used when defining an empty custom loop normals data layer,
|
||||
* to keep same shading as with auto-smooth!
|
||||
*
|
||||
* \param sharp_faces: Optional array used to mark specific faces for sharp shading.
|
||||
*/
|
||||
void BKE_edges_sharp_from_angle_set(int numEdges,
|
||||
const struct MLoop *mloops,
|
||||
int numLoops,
|
||||
const struct MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
int numPolys,
|
||||
float split_angle,
|
||||
bool *sharp_edges);
|
||||
@ -574,6 +577,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space,
|
||||
* (splitting edges).
|
||||
*
|
||||
* \param loop_to_poly_map: Optional pre-created map from loops to their polygon.
|
||||
* \param sharp_faces: Optional array used to mark specific faces for sharp shading.
|
||||
* \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on
|
||||
* each side of the edge.
|
||||
*/
|
||||
@ -591,6 +595,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
|
||||
bool use_split_normals,
|
||||
float split_angle,
|
||||
const bool *sharp_edges,
|
||||
const bool *sharp_faces,
|
||||
const int *loop_to_poly_map,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
short (*clnors_data)[2]);
|
||||
@ -605,6 +610,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
|
||||
int numLoops,
|
||||
const struct MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
int numPolys,
|
||||
bool *sharp_edges,
|
||||
short (*r_clnors_data)[2]);
|
||||
@ -618,6 +624,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
|
||||
int numLoops,
|
||||
const struct MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
int numPolys,
|
||||
bool *sharp_edges,
|
||||
short (*r_clnors_data)[2]);
|
||||
|
@ -96,6 +96,9 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh);
|
||||
void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh);
|
||||
void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_sharp_faces_to_flags(struct Mesh *mesh);
|
||||
void BKE_mesh_legacy_sharp_faces_from_flags(struct Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh);
|
||||
void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh);
|
||||
|
||||
|
@ -324,6 +324,7 @@ int *BKE_mesh_calc_smoothgroups(int totedge,
|
||||
const struct MLoop *mloop,
|
||||
int totloop,
|
||||
const bool *sharp_edges,
|
||||
const bool *sharp_faces,
|
||||
int *r_totgroup,
|
||||
bool use_bitflags);
|
||||
|
||||
|
@ -48,6 +48,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
|
||||
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;
|
||||
|
@ -103,7 +103,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;
|
||||
@ -674,6 +673,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
|
||||
MutableSpan<MEdge> edges = mesh->edges_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
|
||||
|
||||
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
|
||||
fill_mesh_topology(info.vert_range.start(),
|
||||
@ -690,6 +690,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
|
||||
polys);
|
||||
});
|
||||
|
||||
if (fill_caps) {
|
||||
/* TODO: This is used to keep the tests passing after refactoring mesh shade smooth flags. It
|
||||
* can be removed if the tests are updated and the final shading results will be the same. */
|
||||
SpanAttributeWriter<bool> sharp_faces = mesh_attributes.lookup_or_add_for_write_span<bool>(
|
||||
"sharp_face", ATTR_DOMAIN_FACE);
|
||||
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
|
||||
const bool has_caps = fill_caps && !info.main_cyclic && info.profile_cyclic;
|
||||
if (has_caps) {
|
||||
const int poly_num = info.main_segment_num * info.profile_segment_num;
|
||||
const int cap_poly_offset = info.poly_range.start() + poly_num;
|
||||
sharp_faces.span[cap_poly_offset] = true;
|
||||
sharp_faces.span[cap_poly_offset + 1] = true;
|
||||
}
|
||||
});
|
||||
sharp_faces.finish();
|
||||
}
|
||||
|
||||
const Span<float3> main_positions = main.evaluated_positions();
|
||||
const Span<float3> tangents = main.evaluated_tangents();
|
||||
const Span<float3> normals = main.evaluated_normals();
|
||||
@ -721,8 +738,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
|
||||
positions.slice(info.vert_range));
|
||||
});
|
||||
|
||||
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
|
||||
|
||||
SpanAttributeWriter<bool> sharp_edges;
|
||||
write_sharp_bezier_edges(curves_info, offsets, mesh_attributes, sharp_edges);
|
||||
if (fill_caps) {
|
||||
|
@ -382,6 +382,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
|
||||
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"));
|
||||
BKE_mesh_normals_loop_split(positions_dst,
|
||||
BKE_mesh_vert_normals_ensure(me_dst),
|
||||
num_verts_dst,
|
||||
@ -396,6 +398,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
|
||||
use_split_nors_dst,
|
||||
split_angle_dst,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
nullptr,
|
||||
custom_nors_dst);
|
||||
@ -451,6 +454,8 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/,
|
||||
loops_dst.size(),
|
||||
polys_dst.data(),
|
||||
poly_nors_dst,
|
||||
static_cast<const bool *>(CustomData_get_layer_named(
|
||||
&me_dst->pdata, CD_PROP_BOOL, "sharp_face")),
|
||||
polys_dst.size(),
|
||||
sharp_edges.span.data(),
|
||||
custom_nors_dst);
|
||||
@ -1109,26 +1114,21 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
|
||||
return true;
|
||||
}
|
||||
if (r_map && cddata_type == CD_FAKE_SHARP) {
|
||||
const size_t elem_size = sizeof(*((MPoly *)nullptr));
|
||||
const size_t data_size = sizeof(((MPoly *)nullptr)->flag);
|
||||
const size_t data_offset = offsetof(MPoly, flag);
|
||||
const uint64_t data_flag = ME_SMOOTH;
|
||||
|
||||
data_transfer_layersmapping_add_item(r_map,
|
||||
cddata_type,
|
||||
mix_mode,
|
||||
mix_factor,
|
||||
mix_weights,
|
||||
me_src->polys().data(),
|
||||
me_dst->polys_for_write().data(),
|
||||
me_src->totpoly,
|
||||
me_dst->totpoly,
|
||||
elem_size,
|
||||
data_size,
|
||||
data_offset,
|
||||
data_flag,
|
||||
nullptr,
|
||||
interp_data);
|
||||
if (!CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) {
|
||||
CustomData_add_layer_named(
|
||||
&me_dst->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totpoly, "sharp_face");
|
||||
}
|
||||
data_transfer_layersmapping_add_item_cd(
|
||||
r_map,
|
||||
CD_PROP_BOOL,
|
||||
mix_mode,
|
||||
mix_factor,
|
||||
mix_weights,
|
||||
CustomData_get_layer_named(&me_src->pdata, CD_PROP_BOOL, "sharp_face"),
|
||||
CustomData_get_layer_named_for_write(
|
||||
&me_dst->pdata, CD_PROP_BOOL, "sharp_face", num_elem_dst),
|
||||
interp,
|
||||
interp_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_rigidbody_types.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_effect.h"
|
||||
#include "BKE_fluid.h"
|
||||
#include "BKE_global.h"
|
||||
@ -3213,16 +3213,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
|
||||
float size[3];
|
||||
float cell_size_scaled[3];
|
||||
|
||||
/* Assign material + flags to new mesh.
|
||||
* If there are no faces in original mesh, keep materials and flags unchanged. */
|
||||
MPoly mp_example = {0};
|
||||
if (MPoly *polys = BKE_mesh_polys_for_write(orgmesh)) {
|
||||
mp_example = *polys;
|
||||
}
|
||||
|
||||
const int *orig_material_indices = BKE_mesh_material_indices(orgmesh);
|
||||
const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0;
|
||||
const char mp_flag = mp_example.flag;
|
||||
|
||||
int i;
|
||||
int num_verts, num_faces;
|
||||
@ -3251,6 +3243,10 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
|
||||
blender::MutableSpan<MPoly> polys = me->polys_for_write();
|
||||
blender::MutableSpan<MLoop> loops = me->loops_for_write();
|
||||
|
||||
const bool is_sharp = orgmesh->attributes().lookup_or_default<bool>(
|
||||
"sharp_face", ATTR_DOMAIN_FACE, false)[0];
|
||||
BKE_mesh_smooth_flag_set(me, !is_sharp);
|
||||
|
||||
/* Get size (dimension) but considering scaling. */
|
||||
copy_v3_v3(cell_size_scaled, fds->cell_size);
|
||||
mul_v3_v3(cell_size_scaled, ob->scale);
|
||||
@ -3338,7 +3334,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
|
||||
for (const int i : polys.index_range()) {
|
||||
/* Initialize from existing face. */
|
||||
material_indices[i] = mp_mat_nr;
|
||||
polys[i].flag = mp_flag;
|
||||
|
||||
polys[i].loopstart = i * 3;
|
||||
polys[i].totloop = 3;
|
||||
|
@ -913,16 +913,6 @@ static void tag_component_positions_changed(void *owner)
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_shade_smooth(const MPoly &poly)
|
||||
{
|
||||
return poly.flag & ME_SMOOTH;
|
||||
}
|
||||
|
||||
static void set_shade_smooth(MPoly &poly, bool value)
|
||||
{
|
||||
SET_FLAG_FROM_TEST(poly.flag, value, ME_SMOOTH);
|
||||
}
|
||||
|
||||
static float get_crease(const float &crease)
|
||||
{
|
||||
return crease;
|
||||
@ -1217,17 +1207,16 @@ 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::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::Deletable,
|
||||
face_access,
|
||||
make_array_read_attribute<bool>,
|
||||
make_array_write_attribute<bool>,
|
||||
nullptr);
|
||||
|
||||
static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge",
|
||||
ATTR_DOMAIN_EDGE,
|
||||
@ -1259,7 +1248,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, &sharp_edge, &crease},
|
||||
{&position, &id, &material_index, &sharp_face, &sharp_edge, &crease},
|
||||
{&corner_custom_data,
|
||||
&vertex_groups,
|
||||
&point_custom_data,
|
||||
|
@ -2281,6 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
|
||||
&mesh->ldata, CD_CUSTOMLOOPNORMAL, loops.size())); /* May be nullptr. */
|
||||
const bool *sharp_edges = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_split(positions,
|
||||
vert_normals,
|
||||
mesh->totvert,
|
||||
@ -2295,6 +2297,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
|
||||
(mesh->flag & ME_AUTOSMOOTH) != 0,
|
||||
mesh->smoothresh,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
nullptr,
|
||||
clnors);
|
||||
|
@ -1480,7 +1480,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
|
||||
const int count = indices[2] != indices[3] ? 4 : 3;
|
||||
polys[i].loopstart = loop_offset;
|
||||
polys[i].totloop = count;
|
||||
polys[i].flag = ME_SMOOTH;
|
||||
|
||||
mloop[loop_offset].v = uint32_t(indices[0]);
|
||||
mloop[loop_offset + 1].v = uint32_t(indices[1]);
|
||||
|
@ -269,6 +269,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
|
||||
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh);
|
||||
BKE_mesh_legacy_convert_selection_layers_to_flags(mesh);
|
||||
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
|
||||
BKE_mesh_legacy_sharp_faces_to_flags(mesh);
|
||||
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
|
||||
BKE_mesh_legacy_edge_crease_from_layers(mesh);
|
||||
BKE_mesh_legacy_sharp_edges_to_flags(mesh);
|
||||
@ -1485,16 +1486,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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1842,7 +1844,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
|
||||
&mesh->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop);
|
||||
const bool *sharp_edges = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
|
||||
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
const Span<float3> positions = mesh->vert_positions();
|
||||
const Span<MEdge> edges = mesh->edges();
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
@ -1862,6 +1865,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
|
||||
use_split_normals,
|
||||
split_angle,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
r_lnors_spacearr,
|
||||
clnors);
|
||||
|
@ -391,15 +391,12 @@ static void copy_vert_attributes(Mesh *dest_mesh,
|
||||
|
||||
/* Similar to copy_vert_attributes but for poly attributes. */
|
||||
static void copy_poly_attributes(Mesh *dest_mesh,
|
||||
MPoly *poly,
|
||||
const MPoly *orig_poly,
|
||||
const Mesh *orig_me,
|
||||
int poly_index,
|
||||
int index_in_orig_me,
|
||||
Span<short> material_remap,
|
||||
MutableSpan<int> dst_material_indices)
|
||||
{
|
||||
poly->flag = orig_poly->flag;
|
||||
CustomData *target_cd = &dest_mesh->pdata;
|
||||
const CustomData *source_cd = &orig_me->pdata;
|
||||
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
|
||||
@ -751,8 +748,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
||||
}
|
||||
|
||||
copy_poly_attributes(result,
|
||||
poly,
|
||||
orig_poly,
|
||||
orig_me,
|
||||
fi,
|
||||
index_in_orig_me,
|
||||
|
@ -195,6 +195,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);
|
||||
|
||||
blender::float2 *mloopuv = static_cast<blender::float2 *>(CustomData_add_layer_named(
|
||||
&mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, DATA_("UVMap")));
|
||||
|
||||
@ -278,9 +281,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
|
||||
}
|
||||
}
|
||||
|
||||
if (is_smooth) {
|
||||
polys[dst_poly].flag |= ME_SMOOTH;
|
||||
}
|
||||
sharp_faces.span[dst_poly] = !is_smooth;
|
||||
dst_poly++;
|
||||
dst_loop += 3;
|
||||
index += 3;
|
||||
@ -363,9 +364,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
|
||||
}
|
||||
}
|
||||
|
||||
if (is_smooth) {
|
||||
polys[dst_poly].flag |= ME_SMOOTH;
|
||||
}
|
||||
sharp_faces.span[dst_poly] = !is_smooth;
|
||||
dst_poly++;
|
||||
dst_loop += 4;
|
||||
|
||||
@ -383,6 +382,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
|
||||
}
|
||||
|
||||
material_indices.finish();
|
||||
sharp_faces.finish();
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
@ -447,6 +447,12 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
material_indices = static_cast<int *>(CustomData_add_layer_named(
|
||||
pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, totpoly, "material_index"));
|
||||
}
|
||||
bool *sharp_faces = static_cast<bool *>(
|
||||
CustomData_get_layer_named_for_write(pdata, CD_PROP_BOOL, "sharp_face", totpoly));
|
||||
if (!sharp_faces) {
|
||||
sharp_faces = static_cast<bool *>(CustomData_add_layer_named(
|
||||
pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, totpoly, "sharp_face"));
|
||||
}
|
||||
|
||||
numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
|
||||
numCol = CustomData_number_of_layers(fdata, CD_MCOL);
|
||||
@ -491,7 +497,7 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
poly->totloop = mf->v4 ? 4 : 3;
|
||||
|
||||
material_indices[i] = mf->mat_nr;
|
||||
poly->flag = mf->flag;
|
||||
sharp_faces[i] = (mf->flag & ME_SMOOTH) == 0;
|
||||
|
||||
#define ML(v1, v2) \
|
||||
{ \
|
||||
@ -975,6 +981,8 @@ static int mesh_tessface_calc(Mesh &mesh,
|
||||
mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP);
|
||||
const int *material_indices = static_cast<const int *>(
|
||||
CustomData_get_layer_named(pdata, CD_PROP_INT32, "material_index"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
|
||||
/* Allocate the length of `totfaces`, avoid many small reallocation's,
|
||||
* if all faces are triangles it will be correct, `quads == 2x` allocations. */
|
||||
@ -1014,7 +1022,7 @@ static int mesh_tessface_calc(Mesh &mesh,
|
||||
lidx[2] = l3; \
|
||||
lidx[3] = 0; \
|
||||
mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \
|
||||
mf->flag = poly->flag; \
|
||||
mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \
|
||||
mf->edcode = 0; \
|
||||
(void)0
|
||||
|
||||
@ -1037,7 +1045,7 @@ static int mesh_tessface_calc(Mesh &mesh,
|
||||
lidx[2] = l3; \
|
||||
lidx[3] = l4; \
|
||||
mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \
|
||||
mf->flag = poly->flag; \
|
||||
mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \
|
||||
mf->edcode = TESSFACE_IS_QUAD; \
|
||||
(void)0
|
||||
|
||||
@ -1123,7 +1131,6 @@ static int mesh_tessface_calc(Mesh &mesh,
|
||||
lidx[3] = 0;
|
||||
|
||||
mf->mat_nr = material_indices ? material_indices[poly_index] : 0;
|
||||
mf->flag = poly->flag;
|
||||
mf->edcode = 0;
|
||||
|
||||
mface_index++;
|
||||
@ -1214,6 +1221,57 @@ void BKE_mesh_tessface_ensure(struct Mesh *mesh)
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sharp Edge Conversion
|
||||
* \{ */
|
||||
|
||||
void BKE_mesh_legacy_sharp_faces_to_flags(Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
if (const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"))) {
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
SET_FLAG_FROM_TEST(polys[i].flag_legacy, !sharp_faces[i], ME_SMOOTH);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
for (const int i : polys.index_range()) {
|
||||
polys[i].flag_legacy |= ME_SMOOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
if (attributes.contains("sharp_face")) {
|
||||
return;
|
||||
}
|
||||
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
|
||||
return !(poly.flag_legacy & ME_SMOOTH);
|
||||
})) {
|
||||
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
|
||||
"sharp_face", ATTR_DOMAIN_FACE);
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
sharp_faces.span[i] = !(polys[i].flag_legacy & ME_SMOOTH);
|
||||
}
|
||||
});
|
||||
sharp_faces.finish();
|
||||
}
|
||||
else {
|
||||
attributes.remove("sharp_face");
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Face Set Conversion
|
||||
* \{ */
|
||||
@ -1496,7 +1554,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh)
|
||||
".hide_poly", ATTR_DOMAIN_FACE, false);
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
SET_FLAG_FROM_TEST(polys[i].flag, hide_poly[i], ME_HIDE);
|
||||
SET_FLAG_FROM_TEST(polys[i].flag_legacy, hide_poly[i], ME_HIDE);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1539,13 +1597,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
|
||||
}
|
||||
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
if (std::any_of(
|
||||
polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_HIDE; })) {
|
||||
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
|
||||
return poly.flag_legacy & ME_HIDE;
|
||||
})) {
|
||||
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
|
||||
".hide_poly", ATTR_DOMAIN_FACE);
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
hide_poly.span[i] = polys[i].flag & ME_HIDE;
|
||||
hide_poly.span[i] = polys[i].flag_legacy & ME_HIDE;
|
||||
}
|
||||
});
|
||||
hide_poly.finish();
|
||||
@ -1814,7 +1873,7 @@ void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh)
|
||||
".select_poly", ATTR_DOMAIN_FACE, false);
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
SET_FLAG_FROM_TEST(polys[i].flag, select_poly[i], ME_FACE_SEL);
|
||||
SET_FLAG_FROM_TEST(polys[i].flag_legacy, select_poly[i], ME_FACE_SEL);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1858,13 +1917,14 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
|
||||
}
|
||||
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
if (std::any_of(
|
||||
polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_FACE_SEL; })) {
|
||||
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
|
||||
return poly.flag_legacy & ME_FACE_SEL;
|
||||
})) {
|
||||
SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
|
||||
".select_poly", ATTR_DOMAIN_FACE);
|
||||
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
|
||||
for (const int i : range) {
|
||||
select_poly.span[i] = polys[i].flag & ME_FACE_SEL;
|
||||
select_poly.span[i] = polys[i].flag_legacy & ME_FACE_SEL;
|
||||
}
|
||||
});
|
||||
select_poly.finish();
|
||||
|
@ -845,11 +845,14 @@ int *BKE_mesh_calc_smoothgroups(const int totedge,
|
||||
const MLoop *mloop,
|
||||
const int totloop,
|
||||
const bool *sharp_edges,
|
||||
const bool *sharp_faces,
|
||||
int *r_totgroup,
|
||||
const bool use_bitflags)
|
||||
{
|
||||
int *poly_groups = nullptr;
|
||||
|
||||
auto poly_is_smooth = [&](const int i) { return !(sharp_faces && sharp_faces[i]); };
|
||||
|
||||
auto poly_is_island_boundary_smooth = [&](const int poly_index,
|
||||
const int /*loop_index*/,
|
||||
const int edge_index,
|
||||
@ -857,13 +860,13 @@ int *BKE_mesh_calc_smoothgroups(const int totedge,
|
||||
const MeshElemMap &edge_poly_map_elem) {
|
||||
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
|
||||
* or edge is not used by exactly two polygons. */
|
||||
if ((polys[poly_index].flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) &&
|
||||
if ((poly_is_smooth(poly_index)) && !(sharp_edges && sharp_edges[edge_index]) &&
|
||||
(edge_user_count == 2)) {
|
||||
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
|
||||
const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ?
|
||||
edge_poly_map_elem.indices[1] :
|
||||
edge_poly_map_elem.indices[0];
|
||||
return (polys[other_poly_index].flag & ME_SMOOTH) == 0;
|
||||
return !poly_is_smooth(other_poly_index);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
@ -389,6 +389,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
||||
|
||||
const bool *sharp_edges = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&result->edata, CD_PROP_BOOL, "sharp_edge"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_split(BKE_mesh_vert_positions(result),
|
||||
BKE_mesh_vert_normals_ensure(result),
|
||||
result->totvert,
|
||||
@ -403,6 +405,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
||||
true,
|
||||
result->smoothresh,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
&lnors_spacearr,
|
||||
clnors);
|
||||
|
@ -786,6 +786,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
|
||||
const Span<MLoop> loops,
|
||||
const Span<int> loop_to_poly_map,
|
||||
const Span<float3> poly_normals,
|
||||
const Span<bool> sharp_faces,
|
||||
const Span<bool> sharp_edges,
|
||||
const bool check_angle,
|
||||
const float split_angle,
|
||||
@ -794,6 +795,9 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
|
||||
{
|
||||
using namespace blender;
|
||||
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()) {
|
||||
const MPoly &poly = polys[poly_i];
|
||||
@ -808,7 +812,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
|
||||
/* '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] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
|
||||
e2l[1] = (poly_is_smooth(poly_i)) ? INDEX_UNSET : INDEX_INVALID;
|
||||
}
|
||||
else if (e2l[1] == INDEX_UNSET) {
|
||||
const bool is_angle_sharp = (check_angle &&
|
||||
@ -820,7 +824,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
|
||||
* 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 (!(poly.flag & ME_SMOOTH) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
|
||||
if (!poly_is_smooth(poly_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
|
||||
vert_i == loops[e2l[0]].v || is_angle_sharp) {
|
||||
/* NOTE: we are sure that loop != 0 here ;). */
|
||||
e2l[1] = INDEX_INVALID;
|
||||
@ -855,6 +859,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges,
|
||||
const int numLoops,
|
||||
const MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
const int numPolys,
|
||||
const float split_angle,
|
||||
bool *sharp_edges)
|
||||
@ -877,6 +882,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges,
|
||||
{mloops, numLoops},
|
||||
loop_to_poly,
|
||||
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
|
||||
Span<bool>(sharp_faces, sharp_faces ? numPolys : 0),
|
||||
Span<bool>(sharp_edges, numEdges),
|
||||
true,
|
||||
split_angle,
|
||||
@ -1442,6 +1448,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
|
||||
const bool use_split_normals,
|
||||
const float split_angle,
|
||||
const bool *sharp_edges,
|
||||
const bool *sharp_faces,
|
||||
const int *loop_to_poly_map,
|
||||
MLoopNorSpaceArray *r_lnors_spacearr,
|
||||
short (*clnors_data)[2])
|
||||
@ -1465,7 +1472,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
|
||||
const MPoly &poly = polys[poly_index];
|
||||
int ml_index = poly.loopstart;
|
||||
const int ml_index_end = ml_index + poly.totloop;
|
||||
const bool is_poly_flat = ((poly.flag & ME_SMOOTH) == 0);
|
||||
const bool is_poly_flat = sharp_faces && sharp_faces[poly_index];
|
||||
|
||||
for (; ml_index < ml_index_end; ml_index++) {
|
||||
if (is_poly_flat) {
|
||||
@ -1555,6 +1562,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
|
||||
loops,
|
||||
loop_to_poly,
|
||||
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
|
||||
Span<bool>(sharp_faces, sharp_faces ? numPolys : 0),
|
||||
Span<bool>(sharp_edges, sharp_edges ? numEdges : 0),
|
||||
check_angle,
|
||||
split_angle,
|
||||
@ -1605,6 +1613,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
|
||||
const int numLoops,
|
||||
const MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
const int numPolys,
|
||||
MutableSpan<bool> sharp_edges,
|
||||
short (*r_clnors_data)[2],
|
||||
@ -1646,6 +1655,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
|
||||
use_split_normals,
|
||||
split_angle,
|
||||
sharp_edges.data(),
|
||||
sharp_faces,
|
||||
loop_to_poly.data(),
|
||||
&lnors_spacearr,
|
||||
nullptr);
|
||||
@ -1774,6 +1784,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
|
||||
use_split_normals,
|
||||
split_angle,
|
||||
sharp_edges.data(),
|
||||
sharp_faces,
|
||||
loop_to_poly.data(),
|
||||
&lnors_spacearr,
|
||||
nullptr);
|
||||
@ -1848,6 +1859,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
|
||||
const int numLoops,
|
||||
const MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
const int numPolys,
|
||||
bool *sharp_edges,
|
||||
short (*r_clnors_data)[2])
|
||||
@ -1862,6 +1874,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
|
||||
numLoops,
|
||||
polys,
|
||||
poly_normals,
|
||||
sharp_faces,
|
||||
numPolys,
|
||||
{sharp_edges, numEdges},
|
||||
r_clnors_data,
|
||||
@ -1878,6 +1891,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
|
||||
const int numLoops,
|
||||
const MPoly *polys,
|
||||
const float (*poly_normals)[3],
|
||||
const bool *sharp_faces,
|
||||
const int numPolys,
|
||||
bool *sharp_edges,
|
||||
short (*r_clnors_data)[2])
|
||||
@ -1892,6 +1906,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
|
||||
numLoops,
|
||||
polys,
|
||||
poly_normals,
|
||||
sharp_faces,
|
||||
numPolys,
|
||||
{sharp_edges, numEdges},
|
||||
r_clnors_data,
|
||||
@ -1921,7 +1936,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
|
||||
MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
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(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
mesh_normals_loop_custom_set(reinterpret_cast<const float(*)[3]>(positions.data()),
|
||||
BKE_mesh_vert_normals_ensure(mesh),
|
||||
positions.size(),
|
||||
@ -1932,6 +1948,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
BKE_mesh_poly_normals_ensure(mesh),
|
||||
sharp_faces,
|
||||
polys.size(),
|
||||
sharp_edges.span,
|
||||
clnors,
|
||||
|
@ -1361,6 +1361,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||
if (dirty_nors_dst || do_loop_nors_dst) {
|
||||
const bool *sharp_edges = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh_dst->edata, CD_PROP_BOOL, "sharp_edge"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh_dst->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_split(vert_positions_dst,
|
||||
BKE_mesh_vert_normals_ensure(mesh_dst),
|
||||
numverts_dst,
|
||||
@ -1375,6 +1377,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
||||
use_split_nors_dst,
|
||||
split_angle_dst,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
nullptr,
|
||||
custom_nors_dst);
|
||||
|
@ -240,7 +240,7 @@ struct SGLSLMeshToTangent {
|
||||
if (precomputedLoopNormals) {
|
||||
return mikk::float3(precomputedLoopNormals[loop_index]);
|
||||
}
|
||||
if ((polys[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
|
||||
if (sharp_faces && sharp_faces[lt->poly]) { /* flat */
|
||||
if (precomputedFaceNormals) {
|
||||
return mikk::float3(precomputedFaceNormals[lt->poly]);
|
||||
}
|
||||
@ -285,6 +285,7 @@ struct SGLSLMeshToTangent {
|
||||
const float (*vert_normals)[3];
|
||||
const float (*orco)[3];
|
||||
float (*tangent)[4]; /* destination */
|
||||
const bool *sharp_faces;
|
||||
int numTessFaces;
|
||||
|
||||
#ifdef USE_LOOPTRI_DETECT_QUADS
|
||||
@ -394,6 +395,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
|
||||
const MLoop *mloop,
|
||||
const MLoopTri *looptri,
|
||||
const uint looptri_len,
|
||||
const bool *sharp_faces,
|
||||
|
||||
CustomData *loopdata,
|
||||
bool calc_active_tangent,
|
||||
@ -498,6 +500,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
|
||||
mesh2tangent->polys = polys;
|
||||
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;
|
||||
@ -583,6 +586,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
|
||||
me_eval->loops().data(),
|
||||
looptris.data(),
|
||||
uint(looptris.size()),
|
||||
static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&me_eval->pdata, CD_PROP_BOOL, "sharp_face")),
|
||||
&me_eval->ldata,
|
||||
calc_active_tangent,
|
||||
tangent_names,
|
||||
|
@ -151,19 +151,27 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node)
|
||||
// BB_expand(&node->vb, co);
|
||||
//}
|
||||
|
||||
static bool face_materials_match(const PBVH *pbvh, const int a, const int b)
|
||||
static bool face_materials_match(const PBVH *pbvh,
|
||||
const bool *sharp_faces,
|
||||
const int a,
|
||||
const int b)
|
||||
{
|
||||
if (pbvh->material_indices) {
|
||||
if (pbvh->material_indices[a] != pbvh->material_indices[b]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (pbvh->polys[a].flag & ME_SMOOTH) == (pbvh->polys[b].flag & ME_SMOOTH);
|
||||
if (sharp_faces) {
|
||||
if (sharp_faces[a] != sharp_faces[b]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2)
|
||||
{
|
||||
return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr));
|
||||
return (f1->sharp == f2->sharp) && (f1->mat_nr == f2->mat_nr);
|
||||
}
|
||||
|
||||
/* Adapted from BLI_kdopbvh.c */
|
||||
@ -229,7 +237,7 @@ static int partition_indices_grids(int *prim_indices,
|
||||
}
|
||||
|
||||
/* Returns the index of the first element on the right of the partition */
|
||||
static int partition_indices_material(PBVH *pbvh, int lo, int hi)
|
||||
static int partition_indices_material(PBVH *pbvh, const bool *sharp_faces, int lo, int hi)
|
||||
{
|
||||
const MLoopTri *looptri = pbvh->looptri;
|
||||
const DMFlagMat *flagmats = pbvh->grid_flag_mats;
|
||||
@ -239,10 +247,10 @@ static int partition_indices_material(PBVH *pbvh, int lo, int hi)
|
||||
for (;;) {
|
||||
if (pbvh->looptri) {
|
||||
const int first = looptri[pbvh->prim_indices[lo]].poly;
|
||||
for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) {
|
||||
for (; face_materials_match(pbvh, sharp_faces, first, looptri[indices[i]].poly); i++) {
|
||||
/* pass */
|
||||
}
|
||||
for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) {
|
||||
for (; !face_materials_match(pbvh, sharp_faces, first, looptri[indices[j]].poly); j--) {
|
||||
/* pass */
|
||||
}
|
||||
}
|
||||
@ -450,7 +458,7 @@ static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, in
|
||||
|
||||
/* Return zero if all primitives in the node can be drawn with the
|
||||
* same material (including flat/smooth shading), non-zero otherwise */
|
||||
static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
|
||||
static bool leaf_needs_material_split(PBVH *pbvh, const bool *sharp_faces, int offset, int count)
|
||||
{
|
||||
if (count <= 1) {
|
||||
return false;
|
||||
@ -460,7 +468,7 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
|
||||
const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]];
|
||||
for (int i = offset + count - 1; i > offset; i--) {
|
||||
int prim = pbvh->prim_indices[i];
|
||||
if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) {
|
||||
if (!face_materials_match(pbvh, sharp_faces, first->poly, pbvh->looptri[prim].poly)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -539,6 +547,7 @@ static void test_face_boundaries(PBVH *pbvh)
|
||||
*/
|
||||
|
||||
static void build_sub(PBVH *pbvh,
|
||||
const bool *sharp_faces,
|
||||
int node_index,
|
||||
BB *cb,
|
||||
BBC *prim_bbc,
|
||||
@ -557,7 +566,7 @@ static void build_sub(PBVH *pbvh,
|
||||
/* Decide whether this is a leaf or not */
|
||||
const bool below_leaf_limit = count <= pbvh->leaf_limit || depth >= STACK_FIXED_DEPTH - 1;
|
||||
if (below_leaf_limit) {
|
||||
if (!leaf_needs_material_split(pbvh, offset, count)) {
|
||||
if (!leaf_needs_material_split(pbvh, sharp_faces, offset, count)) {
|
||||
build_leaf(pbvh, node_index, prim_bbc, offset, count);
|
||||
|
||||
if (node_index == 0) {
|
||||
@ -610,11 +619,12 @@ static void build_sub(PBVH *pbvh,
|
||||
}
|
||||
else {
|
||||
/* Partition primitives by material */
|
||||
end = partition_indices_material(pbvh, offset, offset + count - 1);
|
||||
end = partition_indices_material(pbvh, sharp_faces, offset, offset + count - 1);
|
||||
}
|
||||
|
||||
/* Build children */
|
||||
build_sub(pbvh,
|
||||
sharp_faces,
|
||||
pbvh->nodes[node_index].children_offset,
|
||||
nullptr,
|
||||
prim_bbc,
|
||||
@ -623,6 +633,7 @@ static void build_sub(PBVH *pbvh,
|
||||
prim_scratch,
|
||||
depth + 1);
|
||||
build_sub(pbvh,
|
||||
sharp_faces,
|
||||
pbvh->nodes[node_index].children_offset + 1,
|
||||
nullptr,
|
||||
prim_bbc,
|
||||
@ -636,7 +647,7 @@ static void build_sub(PBVH *pbvh,
|
||||
}
|
||||
}
|
||||
|
||||
static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
|
||||
static void pbvh_build(PBVH *pbvh, const bool *sharp_faces, BB *cb, BBC *prim_bbc, int totprim)
|
||||
{
|
||||
if (totprim != pbvh->totprim) {
|
||||
pbvh->totprim = totprim;
|
||||
@ -659,7 +670,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
|
||||
}
|
||||
|
||||
pbvh->totnode = 1;
|
||||
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, nullptr, 0);
|
||||
build_sub(pbvh, sharp_faces, 0, cb, prim_bbc, 0, totprim, nullptr, 0);
|
||||
}
|
||||
|
||||
static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
|
||||
@ -881,7 +892,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
|
||||
}
|
||||
|
||||
if (looptri_num) {
|
||||
pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
|
||||
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, looptri_num);
|
||||
|
||||
#ifdef TEST_PBVH_FACE_SPLIT
|
||||
test_face_boundaries(pbvh);
|
||||
@ -968,7 +981,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
|
||||
}
|
||||
|
||||
if (totgrid) {
|
||||
pbvh_build(pbvh, &cb, prim_bbc, totgrid);
|
||||
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&me->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, totgrid);
|
||||
|
||||
#ifdef TEST_PBVH_FACE_SPLIT
|
||||
test_face_boundaries(pbvh);
|
||||
|
@ -116,6 +116,8 @@ bool BKE_shrinkwrap_init_tree(
|
||||
data->mesh = mesh;
|
||||
data->polys = mesh->polys().data();
|
||||
data->vert_normals = BKE_mesh_vert_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};
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
struct CCGMaterialFromMeshData {
|
||||
const Mesh *mesh;
|
||||
blender::Span<MPoly> polys;
|
||||
const bool *sharp_faces;
|
||||
const int *material_indices;
|
||||
};
|
||||
|
||||
@ -24,9 +24,8 @@ static DMFlagMat subdiv_ccg_material_flags_eval(
|
||||
{
|
||||
CCGMaterialFromMeshData *data = (CCGMaterialFromMeshData *)material_flags_evaluator->user_data;
|
||||
BLI_assert(coarse_face_index < data->mesh->totpoly);
|
||||
const MPoly &poly = data->polys[coarse_face_index];
|
||||
DMFlagMat material_flags;
|
||||
material_flags.flag = poly.flag;
|
||||
material_flags.sharp = data->sharp_faces && data->sharp_faces[coarse_face_index];
|
||||
material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0;
|
||||
return material_flags;
|
||||
}
|
||||
@ -45,7 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh(
|
||||
data->mesh = mesh;
|
||||
data->material_indices = (const int *)CustomData_get_layer_named(
|
||||
&mesh->pdata, CD_PROP_INT32, "material_index");
|
||||
data->polys = mesh->polys();
|
||||
data->sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval;
|
||||
material_flags_evaluator->free = subdiv_ccg_material_flags_free;
|
||||
material_flags_evaluator->user_data = data;
|
||||
|
@ -1068,20 +1068,17 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *polys)
|
||||
int gridSize = ccgSubSurf_getGridSize(ss);
|
||||
/* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
|
||||
int i = 0, k = 0;
|
||||
DMFlagMat *faceFlags = ccgdm->faceFlags;
|
||||
|
||||
totface = ccgSubSurf_getNumFaces(ss);
|
||||
for (index = 0; index < totface; index++) {
|
||||
CCGFace *f = ccgdm->faceMap[index].face;
|
||||
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
|
||||
char flag = (faceFlags) ? faceFlags[index].flag : char(ME_SMOOTH);
|
||||
|
||||
for (S = 0; S < numVerts; S++) {
|
||||
for (y = 0; y < gridSize - 1; y++) {
|
||||
for (x = 0; x < gridSize - 1; x++) {
|
||||
polys[i].loopstart = k;
|
||||
polys[i].totloop = 4;
|
||||
polys[i].flag = flag;
|
||||
|
||||
k += 4;
|
||||
i++;
|
||||
@ -1541,9 +1538,11 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
|
||||
gridSideEdges = gridSize - 1;
|
||||
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
|
||||
|
||||
const MPoly *polys = static_cast<const MPoly *>(CustomData_get_layer(&dm->polyData, CD_MPOLY));
|
||||
const int *material_indices = static_cast<const int *>(
|
||||
CustomData_get_layer_named(&dm->polyData, CD_MPOLY, "material_index"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face"));
|
||||
|
||||
const int *base_polyOrigIndex = static_cast<const int *>(
|
||||
CustomData_get_layer(&dm->polyData, CD_ORIGINDEX));
|
||||
|
||||
@ -1569,7 +1568,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
|
||||
ccgdm->faceMap[index].startEdge = edgeNum;
|
||||
ccgdm->faceMap[index].startFace = faceNum;
|
||||
|
||||
faceFlags->flag = polys ? polys[origIndex].flag : 0;
|
||||
faceFlags->sharp = sharp_faces ? sharp_faces[origIndex] : false;
|
||||
faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0;
|
||||
faceFlags++;
|
||||
|
||||
|
@ -180,6 +180,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
|
||||
mesh->loops_for_write());
|
||||
|
||||
BKE_mesh_calc_edges(mesh, false, false);
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utils.h"
|
||||
@ -940,6 +941,139 @@ static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When extruding from loose edges, the extrude geometry node used to create flat faces due to the
|
||||
* default of the old "shade_smooth" attribute. Since the "false" value has changed with the
|
||||
* "sharp_face" attribute, add nodes to propagate the new attribute in its inverted "smooth" form.
|
||||
*/
|
||||
static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree)
|
||||
{
|
||||
using namespace blender;
|
||||
Vector<bNode *> new_nodes;
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
|
||||
if (node->idname != StringRef("GeometryNodeExtrudeMesh")) {
|
||||
continue;
|
||||
}
|
||||
if (static_cast<const NodeGeometryExtrudeMesh *>(node->storage)->mode !=
|
||||
GEO_NODE_EXTRUDE_MESH_EDGES) {
|
||||
continue;
|
||||
}
|
||||
bNodeSocket *geometry_in_socket = nodeFindSocket(node, SOCK_IN, "Mesh");
|
||||
bNodeSocket *geometry_out_socket = nodeFindSocket(node, SOCK_OUT, "Mesh");
|
||||
|
||||
Map<bNodeSocket *, bNodeLink *> in_links_per_socket;
|
||||
MultiValueMap<bNodeSocket *, bNodeLink *> out_links_per_socket;
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
|
||||
in_links_per_socket.add(link->tosock, link);
|
||||
out_links_per_socket.add(link->fromsock, link);
|
||||
}
|
||||
|
||||
bNodeLink *geometry_in_link = in_links_per_socket.lookup_default(geometry_in_socket, nullptr);
|
||||
Span<bNodeLink *> geometry_out_links = out_links_per_socket.lookup(geometry_out_socket);
|
||||
if (!geometry_in_link || geometry_out_links.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool versioning_already_done = [&]() {
|
||||
if (geometry_in_link->fromnode->idname != StringRef("GeometryNodeCaptureAttribute")) {
|
||||
return false;
|
||||
}
|
||||
bNode *capture_node = geometry_in_link->fromnode;
|
||||
const NodeGeometryAttributeCapture &capture_storage =
|
||||
*static_cast<const NodeGeometryAttributeCapture *>(capture_node->storage);
|
||||
if (capture_storage.data_type != CD_PROP_BOOL ||
|
||||
capture_storage.domain != ATTR_DOMAIN_FACE) {
|
||||
return false;
|
||||
}
|
||||
bNodeSocket *capture_in_socket = nodeFindSocket(capture_node, SOCK_IN, "Value_003");
|
||||
bNodeLink *capture_in_link = in_links_per_socket.lookup_default(capture_in_socket, nullptr);
|
||||
if (!capture_in_link) {
|
||||
return false;
|
||||
}
|
||||
if (capture_in_link->fromnode->idname != StringRef("GeometryNodeInputShadeSmooth")) {
|
||||
return false;
|
||||
}
|
||||
if (geometry_out_links.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
bNodeLink *geometry_out_link = geometry_out_links.first();
|
||||
if (geometry_out_link->tonode->idname != StringRef("GeometryNodeSetShadeSmooth")) {
|
||||
return false;
|
||||
}
|
||||
bNode *set_smooth_node = geometry_out_link->tonode;
|
||||
bNodeSocket *smooth_in_socket = nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth");
|
||||
bNodeLink *connecting_link = in_links_per_socket.lookup_default(smooth_in_socket, nullptr);
|
||||
if (!connecting_link) {
|
||||
return false;
|
||||
}
|
||||
if (connecting_link->fromnode != capture_node) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
if (versioning_already_done) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bNode *capture_node = nodeAddNode(nullptr, &ntree, "GeometryNodeCaptureAttribute");
|
||||
capture_node->parent = node->parent;
|
||||
capture_node->locx = node->locx - 25;
|
||||
capture_node->locy = node->locy;
|
||||
new_nodes.append(capture_node);
|
||||
static_cast<NodeGeometryAttributeCapture *>(capture_node->storage)->data_type = CD_PROP_BOOL;
|
||||
static_cast<NodeGeometryAttributeCapture *>(capture_node->storage)->domain = ATTR_DOMAIN_FACE;
|
||||
|
||||
bNode *is_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeInputShadeSmooth");
|
||||
is_smooth_node->parent = node->parent;
|
||||
is_smooth_node->locx = capture_node->locx - 25;
|
||||
is_smooth_node->locy = capture_node->locy;
|
||||
new_nodes.append(is_smooth_node);
|
||||
nodeAddLink(&ntree,
|
||||
is_smooth_node,
|
||||
nodeFindSocket(is_smooth_node, SOCK_OUT, "Smooth"),
|
||||
capture_node,
|
||||
nodeFindSocket(capture_node, SOCK_IN, "Value_003"));
|
||||
nodeAddLink(&ntree,
|
||||
capture_node,
|
||||
nodeFindSocket(capture_node, SOCK_OUT, "Geometry"),
|
||||
capture_node,
|
||||
geometry_in_socket);
|
||||
geometry_in_link->tonode = capture_node;
|
||||
geometry_in_link->tosock = nodeFindSocket(capture_node, SOCK_IN, "Geometry");
|
||||
|
||||
bNode *set_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeSetShadeSmooth");
|
||||
set_smooth_node->parent = node->parent;
|
||||
set_smooth_node->locx = node->locx + 25;
|
||||
set_smooth_node->locy = node->locy;
|
||||
new_nodes.append(set_smooth_node);
|
||||
nodeAddLink(&ntree,
|
||||
node,
|
||||
geometry_out_socket,
|
||||
set_smooth_node,
|
||||
nodeFindSocket(set_smooth_node, SOCK_IN, "Geometry"));
|
||||
|
||||
bNodeSocket *smooth_geometry_out = nodeFindSocket(set_smooth_node, SOCK_OUT, "Geometry");
|
||||
for (bNodeLink *link : geometry_out_links) {
|
||||
link->fromnode = set_smooth_node;
|
||||
link->fromsock = smooth_geometry_out;
|
||||
}
|
||||
nodeAddLink(&ntree,
|
||||
capture_node,
|
||||
nodeFindSocket(capture_node, SOCK_OUT, "Attribute_003"),
|
||||
set_smooth_node,
|
||||
nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth"));
|
||||
}
|
||||
|
||||
/* Move nodes to the front so that they are drawn behind existing nodes. */
|
||||
for (bNode *node : new_nodes) {
|
||||
BLI_remlink(&ntree.nodes, node);
|
||||
BLI_addhead(&ntree.nodes, node);
|
||||
}
|
||||
if (!new_nodes.is_empty()) {
|
||||
nodeRebuildIDVector(&ntree);
|
||||
}
|
||||
}
|
||||
|
||||
void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
|
||||
{
|
||||
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
|
||||
@ -4047,5 +4181,10 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
}
|
||||
}
|
||||
/* Keep this block, even when empty. */
|
||||
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
|
||||
if (ntree->type == NTREE_GEOMETRY) {
|
||||
version_geometry_nodes_extrude_smooth_propagation(*ntree);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
|
||||
BKE_mesh_legacy_convert_flags_to_hide_layers(&mesh);
|
||||
BKE_mesh_legacy_convert_uvs_to_generic(&mesh);
|
||||
BKE_mesh_legacy_convert_mpoly_to_material_indices(&mesh);
|
||||
BKE_mesh_legacy_sharp_faces_from_flags(&mesh);
|
||||
BKE_mesh_legacy_bevel_weight_to_layers(&mesh);
|
||||
BKE_mesh_legacy_sharp_edges_from_flags(&mesh);
|
||||
BKE_mesh_legacy_face_set_to_generic(&mesh);
|
||||
|
@ -113,18 +113,6 @@ using blender::Span;
|
||||
using blender::StringRef;
|
||||
using blender::Vector;
|
||||
|
||||
static char bm_face_flag_from_mflag(const char mflag)
|
||||
{
|
||||
return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0);
|
||||
}
|
||||
|
||||
static char bm_face_flag_to_mflag(const BMFace *f)
|
||||
{
|
||||
const char hflag = f->head.hflag;
|
||||
|
||||
return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0);
|
||||
}
|
||||
|
||||
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
|
||||
{
|
||||
return ELEM(name,
|
||||
@ -137,6 +125,7 @@ bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
|
||||
".select_edge",
|
||||
".select_poly",
|
||||
"material_index",
|
||||
"sharp_face",
|
||||
"sharp_edge");
|
||||
}
|
||||
|
||||
@ -426,6 +415,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
||||
&me->pdata, CD_PROP_BOOL, ".hide_poly");
|
||||
const int *material_indices = (const int *)CustomData_get_layer_named(
|
||||
&me->pdata, CD_PROP_INT32, "material_index");
|
||||
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&me->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
|
||||
&me->edata, CD_PROP_BOOL, "sharp_edge");
|
||||
const bool *uv_seams = (const bool *)CustomData_get_layer_named(
|
||||
@ -527,7 +518,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
|
||||
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
|
||||
|
||||
/* Transfer flag. */
|
||||
f->head.hflag = bm_face_flag_from_mflag(polys[i].flag);
|
||||
if (!(sharp_faces && sharp_faces[i])) {
|
||||
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
|
||||
}
|
||||
if (hide_poly && hide_poly[i]) {
|
||||
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
|
||||
}
|
||||
@ -1252,6 +1245,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
bool need_hide_edge = false;
|
||||
bool need_hide_poly = false;
|
||||
bool need_material_index = false;
|
||||
bool need_sharp_face = false;
|
||||
bool need_sharp_edge = false;
|
||||
bool need_uv_seam = false;
|
||||
|
||||
@ -1312,7 +1306,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
if (f->mat_nr != 0) {
|
||||
need_material_index = true;
|
||||
}
|
||||
polys[i].flag = bm_face_flag_to_mflag(f);
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
|
||||
need_sharp_face = true;
|
||||
}
|
||||
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
need_hide_poly = true;
|
||||
}
|
||||
@ -1357,6 +1353,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
|
||||
return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH);
|
||||
});
|
||||
}
|
||||
if (need_sharp_face) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_FACE);
|
||||
write_fn_to_attribute<bool>(
|
||||
me->attributes_for_write(), "sharp_face", ATTR_DOMAIN_FACE, [&](const int i) {
|
||||
return !BM_elem_flag_test(BM_face_at_index(bm, i), BM_ELEM_SMOOTH);
|
||||
});
|
||||
}
|
||||
if (need_uv_seam) {
|
||||
BM_mesh_elem_table_ensure(bm, BM_EDGE);
|
||||
write_fn_to_attribute<bool>(
|
||||
@ -1524,6 +1527,7 @@ static void bm_face_loop_table_build(BMesh &bm,
|
||||
MutableSpan<const BMLoop *> loop_table,
|
||||
bool &need_select_poly,
|
||||
bool &need_hide_poly,
|
||||
bool &need_sharp_face,
|
||||
bool &need_material_index)
|
||||
{
|
||||
char hflag = 0;
|
||||
@ -1535,6 +1539,7 @@ static void bm_face_loop_table_build(BMesh &bm,
|
||||
BM_elem_index_set(face, face_i); /* set_inline */
|
||||
face_table[face_i] = face;
|
||||
hflag |= face->head.hflag;
|
||||
need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0;
|
||||
need_material_index |= face->mat_nr != 0;
|
||||
|
||||
BMLoop *loop = BM_FACE_FIRST_LOOP(face);
|
||||
@ -1622,6 +1627,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
||||
Mesh &mesh,
|
||||
MutableSpan<bool> select_poly,
|
||||
MutableSpan<bool> hide_poly,
|
||||
MutableSpan<bool> sharp_faces,
|
||||
MutableSpan<int> material_indices)
|
||||
{
|
||||
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
|
||||
@ -1632,7 +1638,6 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
||||
MPoly &dst_poly = dst_polys[face_i];
|
||||
dst_poly.totloop = src_face.len;
|
||||
dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
|
||||
dst_poly.flag = bm_face_flag_to_mflag(&src_face);
|
||||
bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
|
||||
}
|
||||
if (!select_poly.is_empty()) {
|
||||
@ -1650,6 +1655,11 @@ static void bm_to_mesh_faces(const BMesh &bm,
|
||||
material_indices[face_i] = bm_faces[face_i]->mat_nr;
|
||||
}
|
||||
}
|
||||
if (!sharp_faces.is_empty()) {
|
||||
for (const int face_i : range) {
|
||||
sharp_faces[face_i] = !BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SMOOTH);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1721,6 +1731,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
bool need_hide_poly = false;
|
||||
bool need_material_index = false;
|
||||
bool need_sharp_edge = false;
|
||||
bool need_sharp_face = false;
|
||||
bool need_uv_seams = false;
|
||||
Array<const BMVert *> vert_table;
|
||||
Array<const BMEdge *> edge_table;
|
||||
@ -1740,8 +1751,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
[&]() {
|
||||
face_table.reinitialize(bm->totface);
|
||||
loop_table.reinitialize(bm->totloop);
|
||||
bm_face_loop_table_build(
|
||||
*bm, face_table, loop_table, need_select_poly, need_hide_poly, need_material_index);
|
||||
bm_face_loop_table_build(*bm,
|
||||
face_table,
|
||||
loop_table,
|
||||
need_select_poly,
|
||||
need_hide_poly,
|
||||
need_sharp_face,
|
||||
need_material_index);
|
||||
});
|
||||
bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP);
|
||||
|
||||
@ -1756,6 +1772,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
bke::SpanAttributeWriter<bool> uv_seams;
|
||||
bke::SpanAttributeWriter<bool> select_poly;
|
||||
bke::SpanAttributeWriter<bool> hide_poly;
|
||||
bke::SpanAttributeWriter<bool> sharp_face;
|
||||
bke::SpanAttributeWriter<int> material_index;
|
||||
if (need_select_vert) {
|
||||
select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert", ATTR_DOMAIN_POINT);
|
||||
@ -1781,6 +1798,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
if (need_hide_poly) {
|
||||
hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE);
|
||||
}
|
||||
if (need_sharp_face) {
|
||||
sharp_face = attrs.lookup_or_add_for_write_only_span<bool>("sharp_face", ATTR_DOMAIN_FACE);
|
||||
}
|
||||
if (need_material_index) {
|
||||
material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index",
|
||||
ATTR_DOMAIN_FACE);
|
||||
@ -1800,8 +1820,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
uv_seams.span);
|
||||
},
|
||||
[&]() {
|
||||
bm_to_mesh_faces(
|
||||
*bm, face_table, *me, select_poly.span, hide_poly.span, material_index.span);
|
||||
bm_to_mesh_faces(*bm,
|
||||
face_table,
|
||||
*me,
|
||||
select_poly.span,
|
||||
hide_poly.span,
|
||||
sharp_face.span,
|
||||
material_index.span);
|
||||
},
|
||||
[&]() { bm_to_mesh_loops(*bm, loop_table, *me); });
|
||||
|
||||
@ -1813,5 +1838,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
|
||||
uv_seams.finish();
|
||||
select_poly.finish();
|
||||
hide_poly.finish();
|
||||
sharp_face.finish();
|
||||
material_index.finish();
|
||||
}
|
||||
|
@ -383,6 +383,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
|
||||
is_auto_smooth,
|
||||
split_angle,
|
||||
sharp_edges,
|
||||
mr->sharp_faces,
|
||||
nullptr,
|
||||
nullptr,
|
||||
clnors);
|
||||
@ -573,6 +574,9 @@ MeshRenderData *mesh_render_data_create(Object *object,
|
||||
CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".select_edge"));
|
||||
mr->select_poly = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".select_poly"));
|
||||
|
||||
mr->sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
}
|
||||
else {
|
||||
/* #BMesh */
|
||||
|
@ -757,7 +757,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]) {
|
||||
@ -786,7 +786,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);
|
||||
|
@ -336,15 +336,17 @@ struct PBVHBatches {
|
||||
float fno[3];
|
||||
short no[3];
|
||||
int last_poly = -1;
|
||||
bool smooth = false;
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(args->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
|
||||
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri *tri) {
|
||||
bool smooth = false;
|
||||
if (tri->poly != last_poly) {
|
||||
last_poly = tri->poly;
|
||||
|
||||
const MPoly &poly = args->polys[tri->poly];
|
||||
if (!(poly.flag & ME_SMOOTH)) {
|
||||
if (sharp_faces && sharp_faces[tri->poly]) {
|
||||
smooth = true;
|
||||
const MPoly &poly = args->polys[tri->poly];
|
||||
BKE_mesh_calc_poly_normal(
|
||||
&poly, args->mloop + poly.loopstart, args->vert_positions, fno);
|
||||
normal_float_to_short_v3(no, fno);
|
||||
@ -409,7 +411,7 @@ struct PBVHBatches {
|
||||
foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) {
|
||||
float3 no(0.0f, 0.0f, 0.0f);
|
||||
|
||||
const bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
|
||||
const bool smooth = !args->grid_flag_mats[grid_index].sharp;
|
||||
|
||||
if (smooth) {
|
||||
no = CCG_elem_no(&args->ccg_key, elems[0]);
|
||||
@ -1085,7 +1087,7 @@ struct PBVHBatches {
|
||||
|
||||
for (int i : IndexRange(args->totprim)) {
|
||||
int grid_index = args->grid_indices[i];
|
||||
bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
|
||||
bool smooth = !args->grid_flag_mats[grid_index].sharp;
|
||||
BLI_bitmap *gh = args->grid_hidden[grid_index];
|
||||
|
||||
for (int y = 0; y < gridsize - 1; y += skip) {
|
||||
|
@ -94,6 +94,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;
|
||||
|
||||
|
@ -71,11 +71,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 (poly->flag & ME_SMOOTH) {
|
||||
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
|
||||
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
|
||||
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]);
|
||||
}
|
||||
else {
|
||||
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]);
|
||||
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
|
||||
}
|
||||
|
||||
/* Flag for paint mode overlay.
|
||||
@ -195,11 +195,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 (poly->flag & ME_SMOOTH) {
|
||||
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
|
||||
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
|
||||
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]);
|
||||
}
|
||||
else {
|
||||
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]);
|
||||
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
|
||||
}
|
||||
|
||||
/* Flag for paint mode overlay.
|
||||
|
@ -120,6 +120,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
|
||||
mr->loops.data(),
|
||||
mr->looptris.data(),
|
||||
mr->tri_len,
|
||||
mr->sharp_faces,
|
||||
cd_ldata,
|
||||
calc_active_tangent,
|
||||
r_tangent_names,
|
||||
|
@ -800,11 +800,14 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
|
||||
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_edges_sharp_from_angle_set(me->totedge,
|
||||
loops.data(),
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
BKE_mesh_poly_normals_ensure(me),
|
||||
sharp_faces,
|
||||
polys.size(),
|
||||
me->smoothresh,
|
||||
sharp_edges.span.data());
|
||||
@ -1468,6 +1471,8 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const VArray<bool> mesh_sharp_edges = attributes.lookup_or_default<bool>(
|
||||
"sharp_edge", ATTR_DOMAIN_EDGE, false);
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
|
||||
Array<bool> sharp_edges(mesh->totedge);
|
||||
mesh_sharp_edges.materialize(sharp_edges);
|
||||
@ -1477,6 +1482,7 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
BKE_mesh_poly_normals_ensure(mesh),
|
||||
sharp_faces,
|
||||
polys.size(),
|
||||
split_angle,
|
||||
sharp_edges.data());
|
||||
@ -1484,7 +1490,7 @@ void ED_mesh_split_faces(Mesh *mesh)
|
||||
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)) {
|
||||
if (sharp_faces && sharp_faces[poly_i]) {
|
||||
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
|
||||
sharp_edges[loop.e] = true;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
@ -118,6 +119,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);
|
||||
@ -132,8 +134,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) {
|
||||
@ -176,9 +180,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
|
||||
|
||||
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
|
||||
|
||||
if (smooth_normals) {
|
||||
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
|
||||
}
|
||||
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), smooth_normals);
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
ED_sculpt_undo_geometry_end(ob);
|
||||
@ -898,9 +900,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update,
|
||||
|
||||
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
|
||||
|
||||
if (qj->smooth_normals) {
|
||||
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
|
||||
}
|
||||
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), qj->smooth_normals);
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
ED_sculpt_undo_geometry_end(ob);
|
||||
|
@ -419,6 +419,7 @@ struct ProjPaintState {
|
||||
blender::Span<MLoop> loops_eval;
|
||||
const bool *select_poly_eval;
|
||||
const int *material_indices;
|
||||
const bool *sharp_faces_eval;
|
||||
blender::Span<MLoopTri> looptris_eval;
|
||||
|
||||
const float (*mloopuv_stencil_eval)[2];
|
||||
@ -1721,10 +1722,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
|
||||
if (ps->do_mask_normal) {
|
||||
const MLoopTri *lt = &ps->looptris_eval[tri_index];
|
||||
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
|
||||
const MPoly &poly = ps->polys_eval[lt->poly];
|
||||
float no[3], angle_cos;
|
||||
|
||||
if (poly.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]];
|
||||
@ -4079,6 +4079,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
|
||||
&ps->me_eval->pdata, CD_PROP_BOOL, ".select_poly");
|
||||
ps->material_indices = (const int *)CustomData_get_layer_named(
|
||||
&ps->me_eval->pdata, CD_PROP_INT32, "material_index");
|
||||
ps->sharp_faces_eval = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&ps->me_eval->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
|
||||
ps->totvert_eval = ps->me_eval->totvert;
|
||||
ps->totedge_eval = ps->me_eval->totedge;
|
||||
|
@ -400,6 +400,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<float3> vert_positions = me->vert_positions();
|
||||
@ -514,14 +515,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 *poly = &mesh_polys[lt->poly];
|
||||
Material *mat = BKE_object_material_get(ob, material_indices[lt->poly] + 1);
|
||||
|
||||
copy_v3_v3(v1, vert_positions[mesh_loops[lt->tri[0]].v]);
|
||||
@ -536,7 +539,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
|
||||
v2[2] += _z_offset;
|
||||
v3[2] += _z_offset;
|
||||
|
||||
if (_smooth && (poly->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]]);
|
||||
|
@ -407,6 +407,7 @@ Mesh *create_cuboid_mesh(const float3 &size,
|
||||
MutableSpan<float3> positions = mesh->vert_positions_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
calculate_positions(config, positions);
|
||||
|
||||
|
@ -846,7 +846,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
|
||||
options.propagation_info,
|
||||
attributes_to_propagate);
|
||||
attributes_to_propagate.remove("position");
|
||||
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;
|
||||
|
@ -1481,6 +1481,7 @@ struct EdgeFeatData {
|
||||
blender::Span<MLoopTri> looptris;
|
||||
LineartTriangle *tri_array;
|
||||
blender::VArray<bool> sharp_edges;
|
||||
blender::VArray<bool> sharp_faces;
|
||||
LineartVert *v_array;
|
||||
float crease_threshold;
|
||||
bool use_auto_smooth;
|
||||
@ -1648,8 +1649,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
|
||||
if (ld->conf.use_crease) {
|
||||
bool do_crease = true;
|
||||
if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
|
||||
(e_feat_data->polys[looptris[f1].poly].flag & ME_SMOOTH) &&
|
||||
(e_feat_data->polys[looptris[f2].poly].flag & ME_SMOOTH)) {
|
||||
(!e_feat_data->sharp_faces[looptris[f1].poly]) &&
|
||||
(!e_feat_data->sharp_faces[looptris[f2].poly])) {
|
||||
do_crease = false;
|
||||
}
|
||||
if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) {
|
||||
@ -2092,6 +2093,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
|
||||
const bke::AttributeAccessor attributes = me->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);
|
||||
|
||||
EdgeFeatData edge_feat_data = {nullptr};
|
||||
edge_feat_data.ld = la_data;
|
||||
@ -2103,6 +2106,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
|
||||
edge_feat_data.loops = me->loops();
|
||||
edge_feat_data.looptris = looptris;
|
||||
edge_feat_data.sharp_edges = sharp_edges;
|
||||
edge_feat_data.sharp_faces = sharp_faces;
|
||||
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
|
||||
edge_feat_data.tri_array = la_tri_arr;
|
||||
edge_feat_data.v_array = la_v_arr;
|
||||
|
@ -451,7 +451,15 @@ static void get_topology(struct Mesh *mesh,
|
||||
{
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
const Span<MLoop> loops = mesh->loops();
|
||||
r_has_flat_shaded_poly = false;
|
||||
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();
|
||||
loop_counts.clear();
|
||||
@ -463,8 +471,6 @@ static void get_topology(struct Mesh *mesh,
|
||||
const MPoly &poly = polys[i];
|
||||
loop_counts.push_back(poly.totloop);
|
||||
|
||||
r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0;
|
||||
|
||||
const MLoop *loop = &loops[poly.loopstart + (poly.totloop - 1)];
|
||||
|
||||
for (int j = 0; j < poly.totloop; j++, loop--) {
|
||||
|
@ -203,7 +203,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 #71246. */
|
||||
poly.flag |= ME_SMOOTH;
|
||||
|
||||
/* NOTE: Alembic data is stored in the reverse order. */
|
||||
rev_loop_index = loop_index + (face_size - 1);
|
||||
|
@ -615,6 +615,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;
|
||||
|
||||
@ -625,6 +626,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);
|
||||
@ -633,7 +638,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
|
||||
|
||||
for (const int poly_index : polys.index_range()) {
|
||||
const MPoly *poly = &polys[poly_index];
|
||||
bool use_vert_normals = use_custom_normals || poly->flag & ME_SMOOTH;
|
||||
bool use_vert_normals = use_custom_normals || !sharp_faces[poly_index];
|
||||
|
||||
if (!use_vert_normals) {
|
||||
/* For flat faces use face normal as vertex normal: */
|
||||
|
@ -617,6 +617,12 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||
MaterialIdPrimitiveArrayMap mat_prim_map;
|
||||
|
||||
int *material_indices = BKE_mesh_material_indices_for_write(me);
|
||||
bool *sharp_faces = static_cast<bool *>(
|
||||
CustomData_get_layer_named_for_write(&me->pdata, CD_PROP_BOOL, "sharp_face", me->totpoly));
|
||||
if (!sharp_faces) {
|
||||
sharp_faces = static_cast<bool *>(CustomData_add_layer_named(
|
||||
&me->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, me->totpoly, "sharp_face"));
|
||||
}
|
||||
|
||||
COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives();
|
||||
COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals();
|
||||
@ -659,9 +665,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||
if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */
|
||||
/* The same for vertices normals. */
|
||||
uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
|
||||
if (!is_flat_face(vertex_normal_indices, nor, 3)) {
|
||||
polys[poly_index].flag |= ME_SMOOTH;
|
||||
}
|
||||
sharp_faces[poly_index] = is_flat_face(vertex_normal_indices, nor, 3);
|
||||
normal_indices++;
|
||||
}
|
||||
|
||||
@ -729,9 +733,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh,
|
||||
if (mp_has_normals) {
|
||||
/* If it turns out that we have complete custom normals for each MPoly
|
||||
* and we want to use custom normals, this will be overridden. */
|
||||
if (!is_flat_face(normal_indices, nor, vcount)) {
|
||||
polys[poly_index].flag |= ME_SMOOTH;
|
||||
}
|
||||
sharp_faces[poly_index] = is_flat_face(normal_indices, nor, vcount);
|
||||
|
||||
if (use_custom_normals) {
|
||||
/* Store the custom normals for later application. */
|
||||
|
@ -121,6 +121,8 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
} // namespace blender::io::ply
|
||||
|
@ -277,7 +277,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);
|
||||
|
@ -145,7 +145,8 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh,
|
||||
MutableSpan<MPoly> polys = active_mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = active_mesh->loops_for_write();
|
||||
|
||||
const char should_smooth = prim_.IsA<pxr::UsdGeomCube>() ? 0 : ME_SMOOTH;
|
||||
/* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */
|
||||
BKE_mesh_smooth_flag_set(active_mesh, !prim_.IsA<pxr::UsdGeomCube>());
|
||||
|
||||
int loop_index = 0;
|
||||
for (int i = 0; i < face_counts.size(); i++) {
|
||||
@ -155,9 +156,6 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh,
|
||||
poly.loopstart = loop_index;
|
||||
poly.totloop = face_size;
|
||||
|
||||
/* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */
|
||||
poly.flag |= should_smooth;
|
||||
|
||||
for (int f = 0; f < face_size; ++f, ++loop_index) {
|
||||
loops[loop_index].v = face_indices[loop_index];
|
||||
}
|
||||
|
@ -440,12 +440,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_vert_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()
|
||||
@ -194,12 +198,15 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
||||
{
|
||||
const bool *sharp_edges = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&export_mesh_->edata, CD_PROP_BOOL, "sharp_edge"));
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&export_mesh_->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
|
||||
mesh_polys_.data(),
|
||||
mesh_polys_.size(),
|
||||
mesh_loops_.data(),
|
||||
mesh_loops_.size(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
&tot_smooth_groups_,
|
||||
use_bitflags);
|
||||
}
|
||||
@ -245,7 +252,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
|
||||
@ -399,7 +406,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 &poly = mesh_polys_[poly_index];
|
||||
bool need_per_loop_normals = lnors != nullptr || (poly.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 < poly.totloop; ++loop_of_poly) {
|
||||
float3 loop_normal;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "BLI_math_vector_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"
|
||||
@ -40,6 +41,7 @@ class OBJMesh : NonCopyable {
|
||||
Span<MEdge> mesh_edges_;
|
||||
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
|
||||
|
@ -185,9 +185,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;
|
||||
@ -203,9 +205,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
|
||||
MPoly &poly = polys[poly_idx];
|
||||
poly.totloop = curr_face.corner_count_;
|
||||
poly.loopstart = tot_loop_idx;
|
||||
if (curr_face.shaded_smooth) {
|
||||
poly.flag |= ME_SMOOTH;
|
||||
}
|
||||
sharp_faces.span[poly_idx] = !curr_face.shaded_smooth;
|
||||
material_indices.span[poly_idx] = curr_face.material_index;
|
||||
/* Importing obj files without any materials would result in negative indices, which is not
|
||||
* supported. */
|
||||
@ -233,6 +233,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)
|
||||
|
@ -63,19 +63,20 @@ typedef struct MPoly {
|
||||
int totloop;
|
||||
/** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */
|
||||
short mat_nr_legacy;
|
||||
char flag, _pad;
|
||||
char flag_legacy, _pad;
|
||||
} MPoly;
|
||||
|
||||
/** #MPoly.flag */
|
||||
enum {
|
||||
ME_SMOOTH = (1 << 0),
|
||||
#ifdef DNA_DEPRECATED_ALLOW
|
||||
enum {
|
||||
/** Deprecated smooth shading status. Now stored reversed in "sharp_face" attribute. */
|
||||
ME_SMOOTH = (1 << 0),
|
||||
/** Deprecated selection status. Now stored in ".select_poly" attribute. */
|
||||
ME_FACE_SEL = (1 << 1),
|
||||
#endif
|
||||
/** Deprecated hide status. Now stored in ".hide_poly" attribute. */
|
||||
/* ME_HIDE = (1 << 4), */
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Mesh Face Corners.
|
||||
|
@ -90,6 +90,7 @@ DNA_STRUCT_RENAME_ELEM(MDefCell, totinfluence, influences_num)
|
||||
DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MEdge, flag, flag_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MPoly, flag, flag_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MPoly, mat_nr, mat_nr_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MVert, bweight, bweight_legacy)
|
||||
DNA_STRUCT_RENAME_ELEM(MVert, co, co_legacy)
|
||||
|
@ -659,6 +659,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 && sharp_faces[index]);
|
||||
}
|
||||
|
||||
static void rna_MeshPolygon_use_smooth_set(PointerRNA *ptr, bool value)
|
||||
{
|
||||
Mesh *mesh = rna_mesh(ptr);
|
||||
bool *sharp_faces = (bool *)CustomData_get_layer_named_for_write(
|
||||
&mesh->pdata, CD_PROP_BOOL, "sharp_face", mesh->totpoly);
|
||||
if (!sharp_faces) {
|
||||
if (!value) {
|
||||
/* Skip adding layer if the value is the same as the default. */
|
||||
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);
|
||||
@ -1790,8 +1816,9 @@ static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr)
|
||||
{
|
||||
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;
|
||||
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&me->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
return !(sharp_faces && sharp_faces[ltri->poly]);
|
||||
}
|
||||
|
||||
/* path construction */
|
||||
@ -2960,7 +2987,8 @@ 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_boolean_funcs(
|
||||
prop, "rna_MeshPolygon_use_smooth_get", "rna_MeshPolygon_use_smooth_set");
|
||||
RNA_def_property_ui_text(prop, "Smooth", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
|
||||
|
||||
|
@ -93,12 +93,15 @@ static void rna_Mesh_calc_smooth_groups(
|
||||
*r_poly_group_len = mesh->totpoly;
|
||||
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
|
||||
&mesh->edata, CD_PROP_BOOL, "sharp_edge");
|
||||
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
|
||||
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
|
||||
*r_poly_group = BKE_mesh_calc_smoothgroups(mesh->totedge,
|
||||
BKE_mesh_polys(mesh),
|
||||
mesh->totpoly,
|
||||
BKE_mesh_loops(mesh),
|
||||
mesh->totloop,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
r_group_total,
|
||||
use_bitflags);
|
||||
}
|
||||
|
@ -325,7 +325,8 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
|
||||
/* We need to recompute vertex normals! */
|
||||
BKE_mesh_normals_tag_dirty(mesh);
|
||||
}
|
||||
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_custom_set(vert_positions,
|
||||
BKE_mesh_vert_normals_ensure(mesh),
|
||||
verts_num,
|
||||
@ -336,6 +337,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
poly_normals,
|
||||
sharp_faces,
|
||||
polys.size(),
|
||||
sharp_edges,
|
||||
clnors);
|
||||
@ -439,7 +441,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
|
||||
loops, nos, &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) {
|
||||
BKE_mesh_normals_tag_dirty(mesh);
|
||||
}
|
||||
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_custom_set(positions,
|
||||
BKE_mesh_vert_normals_ensure(mesh),
|
||||
verts_num,
|
||||
@ -450,6 +453,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
poly_normals,
|
||||
sharp_faces,
|
||||
polys.size(),
|
||||
sharp_edges,
|
||||
clnors);
|
||||
@ -547,7 +551,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
|
||||
CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, loops.size()));
|
||||
loop_normals = static_cast<float(*)[3]>(
|
||||
MEM_malloc_arrayN(loops.size(), sizeof(*loop_normals), __func__));
|
||||
|
||||
const bool *sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
BKE_mesh_normals_loop_split(positions,
|
||||
vert_normals,
|
||||
verts_num,
|
||||
@ -562,6 +567,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
|
||||
true,
|
||||
result->smoothresh,
|
||||
sharp_edges.span.data(),
|
||||
sharp_faces,
|
||||
nullptr,
|
||||
nullptr,
|
||||
clnors);
|
||||
|
@ -204,7 +204,6 @@ static void generate_ocean_geometry_polys(void *__restrict userdata,
|
||||
|
||||
gogd->polys[fi].loopstart = fi * 4;
|
||||
gogd->polys[fi].totloop = 4;
|
||||
gogd->polys[fi].flag |= ME_SMOOTH;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lib_query.h"
|
||||
@ -191,6 +192,7 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result,
|
||||
|
||||
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData)
|
||||
{
|
||||
using namespace blender;
|
||||
const Mesh *mesh = meshData;
|
||||
Mesh *result;
|
||||
ScrewModifierData *ltmd = (ScrewModifierData *)md;
|
||||
@ -257,7 +259,7 @@ 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;
|
||||
const bool use_flat_shading = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) == 0;
|
||||
|
||||
/* don't do anything? */
|
||||
if (!totvert) {
|
||||
@ -405,6 +407,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
blender::MutableSpan<MEdge> edges_new = result->edges_for_write();
|
||||
blender::MutableSpan<MPoly> polys_new = result->polys_for_write();
|
||||
blender::MutableSpan<MLoop> loops_new = result->loops_for_write();
|
||||
bke::MutableAttributeAccessor attributes = result->attributes_for_write();
|
||||
bke::SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
|
||||
"sharp_face", ATTR_DOMAIN_FACE);
|
||||
|
||||
if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) {
|
||||
CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, int(maxPolys));
|
||||
@ -877,7 +882,7 @@ 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;
|
||||
sharp_faces.span[i] = use_flat_shading;
|
||||
}
|
||||
mp_new->loopstart = mpoly_index * 4;
|
||||
mp_new->totloop = 4;
|
||||
@ -1001,6 +1006,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
}
|
||||
#endif
|
||||
|
||||
sharp_faces.finish();
|
||||
|
||||
if (edge_poly_map) {
|
||||
MEM_freeN(edge_poly_map);
|
||||
}
|
||||
|
@ -1085,7 +1085,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
||||
CustomData_copy_data(
|
||||
&mesh->pdata, &result->pdata, int(pidx), int((polys_num * stride) + i), 1);
|
||||
polys[new_poly_index].loopstart = int(j + (loops_num * stride));
|
||||
polys[new_poly_index].flag = polys[pidx].flag;
|
||||
|
||||
/* notice we use 'polys[new_poly_index].totloop' which is later overwritten,
|
||||
* we could lookup the original face but there's no point since this is a copy
|
||||
|
@ -2320,7 +2320,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
|
||||
dst_material_index[poly_index] = most_mat_nr +
|
||||
(g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim);
|
||||
CLAMP(dst_material_index[poly_index], 0, mat_nr_max);
|
||||
polys[poly_index].flag = orig_polys[most_mat_nr_face].flag;
|
||||
poly_index++;
|
||||
|
||||
for (uint k = 0; g2->valid && k < j; g2++) {
|
||||
@ -2395,7 +2394,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
|
||||
dst_material_index[poly_index] =
|
||||
(src_material_index ? src_material_index[orig_face_index] : 0) + mat_ofs_rim;
|
||||
CLAMP(dst_material_index[poly_index], 0, mat_nr_max);
|
||||
polys[poly_index].flag = face->flag;
|
||||
poly_index++;
|
||||
|
||||
int loop1 = -1;
|
||||
@ -2588,7 +2586,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
|
||||
0) +
|
||||
(fr->reversed != do_flip ? mat_ofs : 0);
|
||||
CLAMP(dst_material_index[poly_index], 0, mat_nr_max);
|
||||
polys[poly_index].flag = fr->face->flag;
|
||||
if (fr->reversed != do_flip) {
|
||||
for (int l = int(k) - 1; l >= 0; l--) {
|
||||
if (shell_defgrp_index != -1) {
|
||||
|
@ -183,9 +183,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
}
|
||||
|
||||
BKE_mesh_copy_parameters_for_eval(mesh, input_mesh);
|
||||
if (vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE) {
|
||||
BKE_mesh_smooth_flag_set(mesh, true);
|
||||
}
|
||||
BKE_mesh_smooth_flag_set(mesh, vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE);
|
||||
return mesh;
|
||||
#else
|
||||
UNUSED_VARS(md);
|
||||
|
@ -83,6 +83,7 @@ struct WeightedNormalData {
|
||||
|
||||
blender::Span<MPoly> polys;
|
||||
const float (*poly_normals)[3];
|
||||
const bool *sharp_faces;
|
||||
const int *poly_strength;
|
||||
|
||||
const MDeformVert *dvert;
|
||||
@ -233,6 +234,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||
true,
|
||||
split_angle,
|
||||
wn_data->sharp_edges,
|
||||
wn_data->sharp_faces,
|
||||
loop_to_poly.data(),
|
||||
&lnors_spacearr,
|
||||
has_clnors ? clnors : nullptr);
|
||||
@ -357,6 +359,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
poly_normals,
|
||||
wn_data->sharp_faces,
|
||||
polys.size(),
|
||||
wn_data->sharp_edges,
|
||||
clnors);
|
||||
@ -389,6 +392,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
poly_normals,
|
||||
wn_data->sharp_faces,
|
||||
polys.size(),
|
||||
wn_data->sharp_edges,
|
||||
clnors);
|
||||
@ -413,6 +417,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||
true,
|
||||
split_angle,
|
||||
wn_data->sharp_edges,
|
||||
wn_data->sharp_faces,
|
||||
loop_to_poly.data(),
|
||||
nullptr,
|
||||
has_clnors ? clnors : nullptr);
|
||||
@ -434,6 +439,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
|
||||
loops.size(),
|
||||
polys.data(),
|
||||
poly_normals,
|
||||
wn_data->sharp_faces,
|
||||
polys.size(),
|
||||
wn_data->sharp_edges,
|
||||
clnors);
|
||||
@ -618,6 +624,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
|
||||
wn_data.polys = polys;
|
||||
wn_data.poly_normals = BKE_mesh_poly_normals_ensure(mesh);
|
||||
wn_data.sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
|
||||
wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named(
|
||||
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID));
|
||||
|
||||
|
@ -43,6 +43,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
|
||||
result = BKE_mesh_new_nomain(verts_num, edges_num, loops_num, faces_num);
|
||||
BKE_id_material_eval_ensure_default_slot(&result->id);
|
||||
}
|
||||
BKE_mesh_smooth_flag_set(result, false);
|
||||
|
||||
/* Copy vertices. */
|
||||
MutableSpan<float3> dst_positions = result->vert_positions_for_write();
|
||||
|
@ -105,6 +105,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result<double> &result)
|
||||
/* The delaunay triangulation doesn't seem to return all of the necessary edges, even in
|
||||
* triangulation mode. */
|
||||
BKE_mesh_calc_edges(mesh, true, false);
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,7 @@ static void transfer_attributes(
|
||||
* Remove anonymous attributes that don't need to be propagated. */
|
||||
Set<AttributeIDRef> attribute_ids = src_attributes.all_ids();
|
||||
attribute_ids.remove("position");
|
||||
attribute_ids.remove("sharp_face");
|
||||
attribute_ids.remove_if([&](const AttributeIDRef &id) {
|
||||
return id.is_anonymous() && !propagation_info.propagate(id.anonymous_id());
|
||||
});
|
||||
@ -887,6 +888,7 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh,
|
||||
}
|
||||
Mesh *mesh_out = BKE_mesh_new_nomain(
|
||||
vert_positions.size(), new_edges.size(), loops.size(), loop_lengths.size());
|
||||
BKE_mesh_smooth_flag_set(mesh_out, false);
|
||||
|
||||
transfer_attributes(vertex_types,
|
||||
keep_boundaries,
|
||||
|
@ -160,7 +160,6 @@ static MPoly new_poly(const int loopstart, const int totloop)
|
||||
MPoly poly;
|
||||
poly.loopstart = loopstart;
|
||||
poly.totloop = totloop;
|
||||
poly.flag = 0;
|
||||
return poly;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -112,6 +112,7 @@ static Mesh *create_circle_mesh(const float radius,
|
||||
MutableSpan<MEdge> edges = mesh->edges_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
/* Assign vertex coordinates. */
|
||||
const float angle_delta = 2.0f * (M_PI / float(verts_num));
|
||||
|
@ -692,6 +692,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
|
||||
MutableSpan<MEdge> edges = mesh->edges_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
calculate_cone_verts(config, positions);
|
||||
calculate_cone_edges(config, edges);
|
||||
|
@ -57,6 +57,7 @@ Mesh *create_grid_mesh(const int verts_x,
|
||||
MutableSpan<MEdge> edges = mesh->edges_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
{
|
||||
const float dx = edges_x == 0 ? 0.0f : size_x / edges_x;
|
||||
|
@ -315,6 +315,7 @@ static Mesh *create_uv_sphere_mesh(const float radius,
|
||||
MutableSpan<MEdge> edges = mesh->edges_for_write();
|
||||
MutableSpan<MPoly> polys = mesh->polys_for_write();
|
||||
MutableSpan<MLoop> loops = mesh->loops_for_write();
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
threading::parallel_invoke(
|
||||
1024 < segments * rings,
|
||||
|
@ -14,36 +14,63 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Geometry>(N_("Geometry")).propagate_all();
|
||||
}
|
||||
|
||||
static void set_smooth(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &shade_field)
|
||||
/**
|
||||
* When the `sharp_face` attribute doesn't exist, all faces are considered smooth. If all faces
|
||||
* are selected and the sharp value is a constant false value, we can remove the attribute instead
|
||||
* as an optimization to avoid storing it and propagating it in the future.
|
||||
*/
|
||||
static bool try_removing_sharp_attribute(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &sharp_field)
|
||||
{
|
||||
if (selection_field.node().depends_on_input() || sharp_field.node().depends_on_input()) {
|
||||
return false;
|
||||
}
|
||||
const bool selection = fn::evaluate_constant_field(selection_field);
|
||||
if (!selection) {
|
||||
return true;
|
||||
}
|
||||
const bool sharp = fn::evaluate_constant_field(sharp_field);
|
||||
if (sharp) {
|
||||
return false;
|
||||
}
|
||||
mesh.attributes_for_write().remove("sharp_face");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_sharp_faces(Mesh &mesh,
|
||||
const Field<bool> &selection_field,
|
||||
const Field<bool> &sharp_field)
|
||||
{
|
||||
if (mesh.totpoly == 0) {
|
||||
return;
|
||||
}
|
||||
if (try_removing_sharp_attribute(mesh, selection_field, sharp_field)) {
|
||||
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);
|
||||
set_sharp_faces(*mesh, selection_field, fn::invert_boolean_field(smooth_field));
|
||||
}
|
||||
});
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
|
@ -141,6 +141,7 @@ static Mesh *create_mesh_from_volume_grids(Span<openvdb::GridBase::ConstPtr> gri
|
||||
}
|
||||
|
||||
BKE_mesh_calc_edges(mesh, false, false);
|
||||
BKE_mesh_smooth_flag_set(mesh, false);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_image.h"
|
||||
@ -450,6 +451,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData,
|
||||
*/
|
||||
static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval)
|
||||
{
|
||||
using namespace blender;
|
||||
int i;
|
||||
|
||||
const int tottri = poly_to_tri_count(me->totpoly, me->totloop);
|
||||
@ -463,6 +465,9 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
|
||||
const float(*positions)[3] = BKE_mesh_vert_positions(me);
|
||||
const blender::Span<MPoly> polys = me->polys();
|
||||
const blender::Span<MLoop> loops = me->loops();
|
||||
const bke::AttributeAccessor attributes = me->attributes();
|
||||
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
|
||||
"sharp_face", ATTR_DOMAIN_FACE, false);
|
||||
|
||||
looptri = static_cast<MLoopTri *>(MEM_mallocN(sizeof(*looptri) * tottri, __func__));
|
||||
triangles = static_cast<TriTessFace *>(MEM_callocN(sizeof(TriTessFace) * tottri, __func__));
|
||||
@ -511,7 +516,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
|
||||
triangles[i].vert_normals[0] = vert_normals[loops[lt->tri[0]].v];
|
||||
triangles[i].vert_normals[1] = vert_normals[loops[lt->tri[1]].v];
|
||||
triangles[i].vert_normals[2] = vert_normals[loops[lt->tri[2]].v];
|
||||
triangles[i].is_smooth = (poly.flag & ME_SMOOTH) != 0;
|
||||
triangles[i].is_smooth = !sharp_faces[lt->poly];
|
||||
|
||||
if (tangent) {
|
||||
triangles[i].tspace[0] = &tspace[lt->tri[0]];
|
||||
|
@ -64,6 +64,7 @@ struct MResolvePixelData {
|
||||
const float (*vert_normals)[3];
|
||||
const MPoly *polys;
|
||||
const int *material_indices;
|
||||
const bool *sharp_faces;
|
||||
MLoop *mloop;
|
||||
float (*mloopuv)[2];
|
||||
float uv_offset[2];
|
||||
@ -114,7 +115,7 @@ static void multiresbake_get_normal(const MResolvePixelData *data,
|
||||
{
|
||||
const int poly_index = data->mlooptri[tri_num].poly;
|
||||
const MPoly &poly = data->polys[poly_index];
|
||||
const bool smoothnormal = (poly.flag & ME_SMOOTH) != 0;
|
||||
const bool smoothnormal = !(data->sharp_faces && data->sharp_faces[poly_index]);
|
||||
|
||||
if (smoothnormal) {
|
||||
const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
|
||||
@ -504,6 +505,8 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
||||
dm->getLoopArray(dm),
|
||||
dm->getLoopTriArray(dm),
|
||||
dm->getNumLoopTri(dm),
|
||||
static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")),
|
||||
&dm->loopData,
|
||||
true,
|
||||
nullptr,
|
||||
@ -550,6 +553,8 @@ static void do_multires_bake(MultiresBakeRender *bkr,
|
||||
handle->data.polys = polys;
|
||||
handle->data.material_indices = static_cast<const int *>(
|
||||
CustomData_get_layer_named(&dm->polyData, CD_PROP_INT32, "material_index"));
|
||||
handle->data.sharp_faces = static_cast<const bool *>(
|
||||
CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face"));
|
||||
handle->data.vert_positions = positions;
|
||||
handle->data.vert_normals = vert_normals;
|
||||
handle->data.mloopuv = mloopuv;
|
||||
|
Loading…
Reference in New Issue
Block a user