Mesh: Replace auto smooth with node group #108014

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

View File

@ -9,7 +9,6 @@
*/
#include "BLI_index_mask.hh"
#include "BLI_virtual_array.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_types.hh"
@ -158,9 +157,9 @@ void normals_calc_loop(Span<float3> vert_positions,
Span<int> loop_to_face_map,
Span<float3> vert_normals,
Span<float3> face_normals,
const VArray<bool> &sharp_edges,
const VArray<bool> &sharp_faces,
const short2 *custom_normals_data,
const bool *sharp_edges,
const bool *sharp_faces,
const short2 *clnors_data,
CornerNormalSpaceArray *r_lnors_spacearr,
MutableSpan<float3> r_loop_normals);
@ -171,7 +170,7 @@ void normals_loop_custom_set(Span<float3> vert_positions,
Span<int> corner_edges,
Span<float3> vert_normals,
Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_loop_normals,
MutableSpan<short2> r_clnors_data);
@ -183,7 +182,7 @@ void normals_loop_custom_set_from_verts(Span<float3> vert_positions,
Span<int> corner_edges,
Span<float3> vert_normals,
Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_vert_normals,
MutableSpan<short2> r_clnors_data);
@ -200,7 +199,7 @@ void edges_sharp_from_angle_set(OffsetIndices<int> faces,
Span<int> corner_verts,
Span<int> corner_edges,
Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
const float split_angle,
MutableSpan<bool> sharp_edges);

View File

@ -13,6 +13,7 @@
#include "BLI_utildefines.h"
struct CustomData;
struct Main;
struct Mesh;
struct MFace;
@ -108,6 +109,8 @@ void BKE_mesh_calc_edges_legacy(Mesh *me);
void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh);
void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain);
/* Inlines */
/* NOTE(@sybren): Instead of -1 that function uses ORIGINDEX_NONE as defined in BKE_customdata.h,

View File

@ -378,8 +378,8 @@ static void data_transfer_dtdata_type_postprocess(Mesh *me_dst,
bke::MutableAttributeAccessor attributes = me_dst->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->face_data, CD_PROP_BOOL, "sharp_face"));
/* Note loop_nors_dst contains our custom normals as transferred from source... */
blender::bke::mesh::normals_loop_custom_set(me_dst->vert_positions(),
me_dst->edges(),

View File

@ -34,7 +34,6 @@
#include "DNA_scene_types.h"
#include "BKE_anim_data.h"
#include "BKE_attribute.hh"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@ -2269,13 +2268,12 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
{reinterpret_cast<blender::float3 *>(vert_normals), mesh->totvert});
}
if (loop_normals_needed) {
const blender::bke::AttributeAccessor attributes = mesh->attributes();
const blender::VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const blender::VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const blender::short2 *clnors = static_cast<const blender::short2 *>(
CustomData_get_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL));
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edge_data, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_calc_loop(
positions,
edges,

View File

@ -1478,12 +1478,14 @@ void BKE_mesh_sharp_edges_set_from_angle(Mesh *me, const float angle)
}
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
bke::mesh::edges_sharp_from_angle_set(me->polys(),
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&me->edge_data, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me->face_data, CD_PROP_BOOL, "sharp_face"));
bke::mesh::edges_sharp_from_angle_set(me->faces(),
me->corner_verts(),
me->corner_edges(),
me->poly_normals(),
me->face_normals(),
sharp_faces,
angle,
sharp_edges.span);

View File

@ -29,9 +29,15 @@
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idprop.hh"
#include "BKE_main.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_legacy_convert.hh"
#include "BKE_modifier.h"
#include "BKE_multires.hh"
#include "BKE_node.hh"
#include "BLT_translation.h"
using blender::MutableSpan;
using blender::Span;
@ -2075,3 +2081,123 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Auto Smooth Conversion
* \{ */
static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
{
bNodeTree *node_tree = ntreeAddTree(&bmain, DATA_("Auto Smooth"), "GeometryNodeTree");
ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketGeometry", DATA_("Geometry"));
ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketFloatAngle", DATA_("Angle"));
ntreeAddSocketInterface(node_tree, SOCK_OUT, "NodeSocketGeometry", DATA_("Geometry"));
bNode *group_input = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_INPUT);
group_input->locx = -380.0f;
bNode *group_output = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_OUTPUT);
group_output->locx = 260.0f;
group_output->flag |= NODE_DO_OUTPUT;
bNode *shade_smooth = nodeAddNode(nullptr, node_tree, "GeometryNodeSetShadeSmooth");
shade_smooth->locx = -160.0f;
shade_smooth->locy = 40.0f;
bNode *store_node = nodeAddNode(nullptr, node_tree, "GeometryNodeStoreNamedAttribute");
store_node->locx = 40.0f;
store_node->locy = 40.0f;
static_cast<NodeGeometryStoreNamedAttribute *>(store_node->storage)->data_type = CD_PROP_BOOL;
static_cast<NodeGeometryStoreNamedAttribute *>(store_node->storage)->domain = ATTR_DOMAIN_EDGE;
bNodeSocket *name = nodeFindSocket(store_node, SOCK_IN, DATA_("Name"));
STRNCPY(name->default_value_typed<bNodeSocketValueString>()->value, "sharp_edge");
HooglyBoogly marked this conversation as resolved Outdated

Don't use more casts than necessary.

Don't use more casts than necessary.
bNode *greater_node = nodeAddNode(nullptr, node_tree, "FunctionNodeCompare");
greater_node->locx = -160.0f;
greater_node->locy = -100.0f;
static_cast<NodeFunctionCompare *>(greater_node->storage)->operation = NODE_COMPARE_GREATER_THAN;
static_cast<NodeFunctionCompare *>(greater_node->storage)->data_type = SOCK_FLOAT;
bNode *edge_angle_node = nodeAddNode(nullptr, node_tree, "GeometryNodeInputMeshEdgeAngle");
edge_angle_node->locx = -380.0f;
edge_angle_node->locy = -180.0f;
nodeAddLink(node_tree,
group_input,
static_cast<bNodeSocket *>(group_input->outputs.first),
shade_smooth,
nodeFindSocket(shade_smooth, SOCK_IN, "Geometry"));
nodeAddLink(node_tree,
shade_smooth,
nodeFindSocket(shade_smooth, SOCK_OUT, "Geometry"),
store_node,
nodeFindSocket(store_node, SOCK_IN, "Geometry"));
nodeAddLink(node_tree,
edge_angle_node,
nodeFindSocket(edge_angle_node, SOCK_OUT, "Unsigned Angle"),
greater_node,
nodeFindSocket(greater_node, SOCK_IN, "A"));
nodeAddLink(node_tree,
group_input,
static_cast<bNodeSocket *>(BLI_findlink(&group_input->outputs, 1)),
greater_node,
nodeFindSocket(greater_node, SOCK_IN, "B"));
nodeAddLink(node_tree,
greater_node,
nodeFindSocket(greater_node, SOCK_OUT, "Result"),
store_node,
nodeFindSocket(store_node, SOCK_IN, "Value_Bool"));
nodeAddLink(node_tree,
store_node,
nodeFindSocket(store_node, SOCK_OUT, "Geometry"),
group_output,
static_cast<bNodeSocket *>(group_output->inputs.first));
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
nodeSetSelected(node, false);
}
return node_tree;
}
void BKE_main_mesh_legacy_convert_auto_smooth(Main &bmain)
{
using namespace blender;
bNodeTree *auto_smooth_node_tree = nullptr;
LISTBASE_FOREACH (Object *, object, &bmain.objects) {
if (object->type != OB_MESH) {
continue;
}
Mesh *mesh = static_cast<Mesh *>(object->data);
if (!(mesh->flag & ME_AUTOSMOOTH)) {
continue;
}
if (CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL)) {
continue;
}
if (!auto_smooth_node_tree) {
auto_smooth_node_tree = add_auto_smooth_node_tree(bmain);
}
auto *md = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
STRNCPY(md->modifier.name, DATA_("Auto Smooth"));
BKE_modifier_unique_name(&object->modifiers, &md->modifier);
md->node_group = auto_smooth_node_tree;
if (!BLI_listbase_is_empty(&object->modifiers) &&
static_cast<ModifierData *>(object->modifiers.last)->type == eModifierType_Subsurf)
{
/* Add the auto smooth node group before the last subdivision surface modifier if possible.
* Subdivision surface modifiers have special handling for interpolating face corner normals,
* and recalculating them afterwards isn't usually helpful and can be much slower. */
BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, md);
}
else {
BLI_addtail(&object->modifiers, md);
}
md->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
IDProperty *angle_prop = bke::idprop::create(DATA_("Input_1"), mesh->smoothresh).release();
IDP_AddToGroup(md->settings.properties, angle_prop);
}

MOD_nodes_update_interface(object, md);?

`MOD_nodes_update_interface(object, md);`?

Maybe. I'd rather not bring in another "MOD" include to the blenkernel though, theoretically the dependency is supposed to be in the other direction. I'm investigating just importing the asset here anyway, that might simplify things.

Maybe. I'd rather not bring in another "MOD" include to the blenkernel though, theoretically the dependency is supposed to be in the other direction. I'm investigating just importing the asset here anyway, that might simplify things.
}
/** \} */

View File

@ -406,11 +406,10 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
const blender::bke::AttributeAccessor attributes = result->attributes();
const blender::VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const blender::VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&result->edge_data, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&result->face_data, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_calc_loop(result->vert_positions(),
result_edges,
result_faces,

View File

@ -437,14 +437,12 @@ blender::Span<blender::float3> Mesh::corner_normals() const
break;
}
case ATTR_DOMAIN_CORNER: {
const AttributeAccessor attributes = this->attributes();
const VArray<bool> sharp_edges = *attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&this->edge_data, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&this->face_data, CD_PROP_BOOL, "sharp_face"));
const short2 *custom_normals = static_cast<const short2 *>(
CustomData_get_layer(&this->loop_data, CD_CUSTOMLOOPNORMAL));
bke::mesh::normals_calc_loop(this->vert_positions(),
this->edges(),
this->faces(),
@ -821,14 +819,17 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
const Span<int> corner_edges,
const Span<int> loop_to_face_map,
const Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const VArray<bool> &sharp_edges,
const Span<bool> sharp_faces,
const Span<bool> sharp_edges,
const bool check_angle,
const float split_angle,
MutableSpan<int2> edge_to_loops,
MutableSpan<bool> r_sharp_edges)
{
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
auto face_is_smooth = [&](const int face_i) {
return sharp_faces.is_empty() || !sharp_faces[face_i];
};
for (const int face_i : faces.index_range()) {
for (const int loop_index : faces[face_i]) {
@ -842,7 +843,7 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = sharp_faces[face_i] ? INDEX_INVALID : INDEX_UNSET;
e2l[1] = face_is_smooth(face_i) ? INDEX_UNSET : INDEX_INVALID;
}
else if (e2l[1] == INDEX_UNSET) {
const bool is_angle_sharp = (check_angle &&
@ -854,14 +855,15 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
* or both faces have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its faces' normals is above split_angle value.
*/
if (sharp_faces[face_i] || sharp_edges[edge_i] || vert_i == corner_verts[e2l[0]] ||
is_angle_sharp) {
if (!face_is_smooth(face_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
vert_i == corner_verts[e2l[0]] || is_angle_sharp)
{
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */
if (is_angle_sharp) {
if (!r_sharp_edges.is_empty() && is_angle_sharp) {
r_sharp_edges[edge_i] = true;
}
}
@ -885,10 +887,13 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> faces,
static void build_edge_to_loop_map(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<int> corner_edges,
const VArray<bool> &sharp_faces,
const VArray<bool> &sharp_edges,
const Span<bool> sharp_faces,
const Span<bool> sharp_edges,
MutableSpan<int2> edge_to_loops)
{
auto face_is_smooth = [&](const int face_i) {
return sharp_faces.is_empty() || !sharp_faces[face_i];
};
for (const int face_i : faces.index_range()) {
for (const int loop_index : faces[face_i]) {
@ -902,14 +907,16 @@ static void build_edge_to_loop_map(const OffsetIndices<int> faces,
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = sharp_faces[face_i] ? INDEX_INVALID : INDEX_UNSET;
e2l[1] = !face_is_smooth(face_i) ? INDEX_INVALID : INDEX_UNSET;
}
else if (e2l[1] == INDEX_UNSET) {
/* Second loop using this edge, time to test its sharpness.
* An edge is sharp if it is tagged as such, or its face is not smooth,
* or both face have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex. */
if (sharp_faces[face_i] || sharp_edges[edge_i] || vert_i == corner_verts[e2l[0]]) {
if (!face_is_smooth(face_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
vert_i == corner_verts[e2l[0]])
{
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
}
@ -930,7 +937,7 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> faces,
const Span<int> corner_verts,
const Span<int> corner_edges,
const Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
const float split_angle,
MutableSpan<bool> sharp_edges)
{
@ -950,8 +957,8 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> faces,
corner_edges,
loop_to_face,
face_normals,
sharp_faces,
VArray<bool>::ForSpan(sharp_edges),
Span<bool>(sharp_faces, sharp_faces ? faces.size() : 0),
sharp_edges,
true,
split_angle,
edge_to_loops,
@ -1347,9 +1354,9 @@ void normals_calc_loop(const Span<float3> vert_positions,
const Span<int> loop_to_face_map,
const Span<float3> vert_normals,
const Span<float3> face_normals,
const VArray<bool> &sharp_edges,
const VArray<bool> &sharp_faces,
const short2 *custom_normals_data,
const bool *sharp_edges,
const bool *sharp_faces,
const short2 *clnors_data,
CornerNormalSpaceArray *r_lnors_spacearr,
MutableSpan<float3> r_loop_normals)
{
@ -1386,7 +1393,7 @@ void normals_calc_loop(const Span<float3> vert_positions,
SCOPED_TIMER_AVERAGED(__func__);
#endif
if (!r_lnors_spacearr && custom_normals_data) {
if (!r_lnors_spacearr && clnors_data) {
/* We need to compute lnor spacearr if some custom lnor data are given to us! */
r_lnors_spacearr = &_lnors_spacearr;
}
@ -1395,7 +1402,7 @@ void normals_calc_loop(const Span<float3> vert_positions,
LoopSplitTaskDataCommon common_data;
common_data.lnors_spacearr = r_lnors_spacearr;
common_data.loop_normals = r_loop_normals;
common_data.clnors_data = {custom_normals_data, custom_normals_data ? corner_verts.size() : 0};
common_data.clnors_data = {clnors_data, clnors_data ? corner_verts.size() : 0};
common_data.positions = vert_positions;
common_data.edges = edges;
common_data.faces = faces;
@ -1411,8 +1418,12 @@ void normals_calc_loop(const Span<float3> vert_positions,
array_utils::gather(vert_normals, corner_verts, r_loop_normals, 1024);
/* This first loop check which edges are actually smooth, and compute edge vectors. */
build_edge_to_loop_map(
faces, corner_verts, corner_edges, sharp_faces, sharp_edges, edge_to_loops);
build_edge_to_loop_map(faces,
corner_verts,
corner_edges,
Span<bool>(sharp_faces, sharp_faces ? faces.size() : 0),
Span<bool>(sharp_edges, sharp_edges ? edges.size() : 0),
edge_to_loops);
Vector<int> single_corners;
Vector<int> fan_corners;
@ -1464,7 +1475,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
Span<int> corner_edges,
Span<float3> vert_normals,
Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
const bool use_vertices,
MutableSpan<float3> r_custom_loop_normals,
MutableSpan<bool> sharp_edges,
@ -1490,7 +1501,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
loop_to_face,
vert_normals,
face_normals,
VArray<bool>::ForSpan(sharp_edges),
sharp_edges.data(),
sharp_faces,
r_clnors_data.data(),
&lnors_spacearr,
@ -1610,7 +1621,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
loop_to_face,
vert_normals,
face_normals,
VArray<bool>::ForSpan(sharp_edges),
sharp_edges.data(),
sharp_faces,
r_clnors_data.data(),
&lnors_spacearr,
@ -1668,7 +1679,7 @@ void normals_loop_custom_set(const Span<float3> vert_positions,
const Span<int> corner_edges,
const Span<float3> vert_normals,
const Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_loop_normals,
MutableSpan<short2> r_clnors_data)
@ -1694,7 +1705,7 @@ void normals_loop_custom_set_from_verts(const Span<float3> vert_positions,
const Span<int> corner_edges,
const Span<float3> vert_normals,
const Span<float3> face_normals,
const VArray<bool> &sharp_faces,
const bool *sharp_faces,
MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_vert_normals,
MutableSpan<short2> r_clnors_data)
@ -1727,8 +1738,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 VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
mesh_normals_loop_custom_set(
mesh->vert_positions(),

View File

@ -2,6 +2,7 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_attribute.h"
#include "BKE_subdiv_modifier.hh"
#include "MEM_guardedalloc.h"

View File

@ -15,7 +15,6 @@
#include "DNA_brush_types.h"
#include "DNA_light_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_scene_types.h"
@ -31,16 +30,13 @@
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "BKE_attribute.hh"
#include "BKE_effect.h"
#include "BKE_grease_pencil.hh"
#include "BKE_idprop.hh"
#include "BKE_main.h"
#include "BKE_mesh_legacy_convert.hh"
#include "BKE_modifier.h"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@ -49,130 +45,12 @@
#include "BLO_read_write.h"
#include "BLO_readfile.h"
#include "BLT_translation.h"
#include "readfile.h"
#include "versioning_common.h"
// static CLG_LogRef LOG = {"blo.readfile.doversion"};
static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
{
bNodeTree *node_tree = ntreeAddTree(&bmain, DATA_("Auto Smooth"), "GeometryNodeTree");
ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketGeometry", DATA_("Geometry"));
ntreeAddSocketInterface(node_tree, SOCK_IN, "NodeSocketFloatAngle", DATA_("Angle"));
ntreeAddSocketInterface(node_tree, SOCK_OUT, "NodeSocketGeometry", DATA_("Geometry"));
bNode *group_input = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_INPUT);
group_input->locx = -380.0f;
bNode *group_output = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_OUTPUT);
group_output->locx = 260.0f;
group_output->flag |= NODE_DO_OUTPUT;
bNode *shade_smooth = nodeAddNode(nullptr, node_tree, "GeometryNodeSetShadeSmooth");
shade_smooth->locx = -160.0f;
shade_smooth->locy = 40.0f;
bNode *store_node = nodeAddNode(nullptr, node_tree, "GeometryNodeStoreNamedAttribute");
store_node->locx = 40.0f;
store_node->locy = 40.0f;
static_cast<NodeGeometryStoreNamedAttribute *>(store_node->storage)->data_type = CD_PROP_BOOL;
static_cast<NodeGeometryStoreNamedAttribute *>(store_node->storage)->domain = ATTR_DOMAIN_EDGE;
bNodeSocket *name = nodeFindSocket(store_node, SOCK_IN, DATA_("Name"));
STRNCPY(name->default_value_typed<bNodeSocketValueString>()->value, "sharp_edge");
bNode *greater_node = nodeAddNode(nullptr, node_tree, "FunctionNodeCompare");
greater_node->locx = -160.0f;
greater_node->locy = -100.0f;
static_cast<NodeFunctionCompare *>(greater_node->storage)->operation = NODE_COMPARE_GREATER_THAN;
static_cast<NodeFunctionCompare *>(greater_node->storage)->data_type = SOCK_FLOAT;
bNode *edge_angle_node = nodeAddNode(nullptr, node_tree, "GeometryNodeInputMeshEdgeAngle");
edge_angle_node->locx = -380.0f;
edge_angle_node->locy = -180.0f;
nodeAddLink(node_tree,
group_input,
static_cast<bNodeSocket *>(group_input->outputs.first),
shade_smooth,
nodeFindSocket(shade_smooth, SOCK_IN, "Geometry"));
nodeAddLink(node_tree,
shade_smooth,
nodeFindSocket(shade_smooth, SOCK_OUT, "Geometry"),
store_node,
nodeFindSocket(store_node, SOCK_IN, "Geometry"));
nodeAddLink(node_tree,
edge_angle_node,
nodeFindSocket(edge_angle_node, SOCK_OUT, "Unsigned Angle"),
greater_node,
nodeFindSocket(greater_node, SOCK_IN, "A"));
nodeAddLink(node_tree,
group_input,
static_cast<bNodeSocket *>(BLI_findlink(&group_input->outputs, 1)),
greater_node,
nodeFindSocket(greater_node, SOCK_IN, "B"));
nodeAddLink(node_tree,
greater_node,
nodeFindSocket(greater_node, SOCK_OUT, "Result"),
store_node,
nodeFindSocket(store_node, SOCK_IN, "Value_Bool"));
nodeAddLink(node_tree,
store_node,
nodeFindSocket(store_node, SOCK_OUT, "Geometry"),
group_output,
static_cast<bNodeSocket *>(group_output->inputs.first));
LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) {
nodeSetSelected(node, false);
}
version_socket_update_is_used(node_tree);
return node_tree;
}
static void version_mesh_objects_replace_auto_smooth(Main &bmain)
{
using namespace blender;
bNodeTree *auto_smooth_node_tree = nullptr;
LISTBASE_FOREACH (Object *, object, &bmain.objects) {
if (object->type != OB_MESH) {
continue;
}
Mesh *mesh = static_cast<Mesh *>(object->data);
if (!(mesh->flag & ME_AUTOSMOOTH)) {
continue;
}
if (CustomData_has_layer(&mesh->loop_data, CD_CUSTOMLOOPNORMAL)) {
continue;
}
if (!auto_smooth_node_tree) {
auto_smooth_node_tree = add_auto_smooth_node_tree(bmain);
}
auto *md = reinterpret_cast<NodesModifierData *>(BKE_modifier_new(eModifierType_Nodes));
STRNCPY(md->modifier.name, DATA_("Auto Smooth"));
BKE_modifier_unique_name(&object->modifiers, &md->modifier);
md->node_group = auto_smooth_node_tree;
if (!BLI_listbase_is_empty(&object->modifiers) &&
static_cast<ModifierData *>(object->modifiers.last)->type == eModifierType_Subsurf)
{
/* Add the auto smooth node group before the last subdivision surface modifier if possible.
* Subdivision surface modifiers have special handling for interpolating face corner normals,
* and recalculating them afterwards isn't usually helpful and can be much slower. */
BLI_insertlinkbefore(&object->modifiers, object->modifiers.last, md);
}
else {
BLI_addtail(&object->modifiers, md);
}
md->settings.properties = bke::idprop::create_group("Nodes Modifier Settings").release();
IDProperty *angle_prop = bke::idprop::create(DATA_("Input_1"), mesh->smoothresh).release();
IDP_AddToGroup(md->settings.properties, angle_prop);
}
}
static void version_composite_nodetree_null_id(bNodeTree *ntree, Scene *scene)
{
for (bNode *node : ntree->all_nodes()) {
@ -244,10 +122,6 @@ void do_versions_after_linking_400(FileData *fd, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 16)) {
version_mesh_objects_replace_auto_smooth(*bmain);
}
/**
* Versioning code until next subversion bump goes here.
*

View File

@ -25,6 +25,7 @@
#include "BKE_lib_override.hh"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
#include "BKE_mesh_legacy_convert.hh"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
@ -525,4 +526,8 @@ void do_versions_after_setup(Main *new_bmain, BlendFileReadReport *reports)
/* Does not add any new IDs, but needs the full Main data-base. */
BKE_lib_override_library_main_hierarchy_root_ensure(new_bmain);
}
if (!blendfile_or_libraries_versions_atleast(new_bmain, 400, 16)) {
BKE_main_mesh_legacy_convert_auto_smooth(*new_bmain);
}
}

View File

@ -13,8 +13,6 @@
* To update preference defaults see `userdef_default.c`.
*/
#define DNA_DEPRECATED_ALLOW
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"

View File

@ -6,6 +6,8 @@
* will be rendered in the default view. No additional setup required.
*/
#ifdef DRW_DEBUG_DRAW
/** Global switch option. */
bool drw_debug_draw_enable = true;
const vec4 drw_debug_default_color = vec4(1.0, 0.0, 0.0, 1.0);
@ -212,4 +214,6 @@ void drw_debug_matrix_as_bbox(mat4 mat)
drw_debug_matrix_as_bbox(mat, drw_debug_default_color);
}
#endif
/** \} */

View File

@ -30,6 +30,8 @@
* in sync to write the same data.
*/
#ifdef DRW_DEBUG_PRINT
/** Global switch option when you want to silence all prints from all shaders at once. */
bool drw_debug_print_enable = true;
@ -202,7 +204,7 @@ void drw_print_value(int value)
drw_print_value_uint(uint(abs(value)), false, (value < 0), false);
}
#ifndef GPU_METAL
# ifndef GPU_METAL
void drw_print_value(bool value)
{
@ -214,7 +216,7 @@ void drw_print_value(bool value)
}
}
#endif
# endif
/* NOTE(@fclem): This is homebrew and might not be 100% accurate (accuracy has
* not been tested and might dependent on compiler implementation). If unsure,
@ -246,6 +248,12 @@ void drw_print_value(float val)
bool display_exponent = exponent >= (significant_digits) ||
exponent <= (-significant_digits + 1.0);
if (exponent < -1.0) {
/* FIXME(fclem): Display of values with exponent from -1 to -5 is broken. Force scientific
* notation in these cases. */
display_exponent = true;
}
float int_significant_digits = min(exponent + 1.0, significant_digits);
float dec_significant_digits = max(0.0, significant_digits - int_significant_digits);
/* Power to get to the rounding point. */
@ -290,8 +298,7 @@ void drw_print_value(float val)
}
/* Decimal part. */
value = uint(abs(dec_part));
#if 0 /* We don't do that because it makes unstable values really hard to \
read. */
# if 0 /* We don't do that because it makes unstable values really hard to read. */
/* Trim trailing zeros. */
while ((value % base) == 0u) {
value /= base;
@ -299,7 +306,7 @@ void drw_print_value(float val)
break;
}
}
#endif
# endif
if (value != 0u) {
for (int i = 0; value != 0u || i == 0; i++, value /= base) {
drw_print_append_digit(value % base, digits[digit / 4u]);
@ -409,3 +416,5 @@ void drw_print_value(mat3 value)
drw_print(" ", value[2]);
drw_print(")");
}
#endif

View File

@ -12,6 +12,7 @@
* \{ */
GPU_SHADER_CREATE_INFO(draw_debug_print)
.define("DRW_DEBUG_PRINT")
.typedef_source("draw_shader_shared.h")
.storage_buf(DRW_DEBUG_PRINT_SLOT, Qualifier::READ_WRITE, "uint", "drw_debug_print_buf[]");
@ -37,6 +38,7 @@ GPU_SHADER_CREATE_INFO(draw_debug_print_display)
* \{ */
GPU_SHADER_CREATE_INFO(draw_debug_draw)
.define("DRW_DEBUG_DRAW")
.typedef_source("draw_shader_shared.h")
.storage_buf(DRW_DEBUG_DRAW_SLOT,
Qualifier::READ_WRITE,

View File

@ -1124,21 +1124,22 @@ Mesh *ED_mesh_context(bContext *C)
void ED_mesh_split_faces(Mesh *mesh)
{
using namespace blender;
const OffsetIndices faces = mesh->faces();
const OffsetIndices polys = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges();
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> mesh_sharp_edges = *attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
Array<bool> sharp_edges(mesh->totedge);
mesh_sharp_edges.materialize(sharp_edges);
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int face_i : range) {
if (sharp_faces && sharp_faces[face_i]) {
for (const int edge : corner_edges.slice(faces[face_i])) {
for (const int edge : corner_edges.slice(polys[face_i])) {
sharp_edges[edge] = true;
}
}

View File

@ -2064,7 +2064,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = NULL; /* BKE_editmesh_from_object(t->obedit); */
BMEditMesh *em = nullptr; /* BKE_editmesh_from_object(t->obedit); */
bool do_skip = false;
/* Currently only used for two of three most frequent transform ops,

View File

@ -422,8 +422,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {mlooptri, tottri});
const blender::Span<int> looptri_faces = me->looptri_faces();
const blender::Span<blender::float3> corner_normals = me->corner_normals();
const blender::Span<blender::float3> lnors = me->corner_normals();
// Get other mesh data
const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&me->edge_data,
@ -541,9 +540,9 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
v3[2] += _z_offset;
if (_smooth && (!sharp_faces[poly_i])) {
copy_v3_v3(n1, corner_normals[lt->tri[0]]);
copy_v3_v3(n2, corner_normals[lt->tri[1]]);
copy_v3_v3(n3, corner_normals[lt->tri[2]]);
copy_v3_v3(n1, lnors[lt->tri[0]]);
copy_v3_v3(n2, lnors[lt->tri[1]]);
copy_v3_v3(n3, lnors[lt->tri[2]]);
mul_mat3_m4_v3(nmat, n1);
mul_mat3_m4_v3(nmat, n2);

View File

@ -556,7 +556,7 @@ static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
threading::parallel_for(faces.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
const IndexRange face = faces[i];
for (const int i : IndexRange(face.size())) {
for (const int i : face.index_range()) {
copy_yup_from_zup(dst_normals[face.last(i)], corner_normals[face[i]]);
}
}

View File

@ -625,12 +625,14 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const blender::Span<blender::float3> corner_normals = me->corner_normals();
bool use_custom_normals = true;
blender::Span<blender::float3> corner_normals;
if (me->normal_domain_all_info() == ATTR_DOMAIN_CORNER) {
corner_normals = me->corner_normals();
}
for (const int face_index : faces.index_range()) {
const IndexRange face = faces[face_index];
bool use_vert_normals = use_custom_normals || !sharp_faces[face_index];
bool use_vert_normals = !corner_normals.is_empty() || !sharp_faces[face_index];
if (!use_vert_normals) {
/* For flat faces use face normal as vertex normal: */
@ -648,7 +650,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
if (use_vert_normals) {
float normalized[3];
if (use_custom_normals) {
if (!corner_normals.is_empty()) {
normalize_v3_v3(normalized, corner_normals[corner]);
}
else {

View File

@ -153,9 +153,6 @@ typedef struct Mesh {
/** Mostly more flags used when editing or displaying the mesh. */
uint16_t flag;
/**
* The angle for auto smooth in radians. `M_PI` (180 degrees) causes all edges to be smooth.
*/
float smoothresh DNA_DEPRECATED;
/** Per-mesh settings for voxel remesh. */
@ -356,7 +353,7 @@ typedef struct Mesh {
* face corner normals, since there is a 2-4x performance cost increase for each more complex
* domain.
*/
eAttrDomain normal_domain_all_info() const;
int normal_domain_all_info() const;
/**
* Normal direction of polygons, defined by positions and the winding direction of face corners.
*/
@ -371,7 +368,7 @@ typedef struct Mesh {
* normals, the `sharp_edge` and `sharp_face` attributes, and potentially by custom normals.
*
HooglyBoogly marked this conversation as resolved Outdated

I wonder if we could call this normals_domain. I found "all info" more confusing than useful at first.

I wonder if we could call this `normals_domain`. I found "all info" more confusing than useful at first.
* \note Because of the large memory requirements of storing normals per face corner, prefer
* using #poly_normals() or #vert_normals() when possible (see #normal_domain_all_info()).
* using #face_normals() or #vert_normals() when possible (see #normal_domain_all_info()).
*/
blender::Span<blender::float3> corner_normals() const;
#endif

View File

@ -232,9 +232,6 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
blender::MutableSpan<int> corner_edges,
const blender::OffsetIndices<int> faces)
{
using namespace blender;
const bke::AttributeAccessor attributes = mesh->attributes();
Object *ob_target = enmd->target;
const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
@ -324,8 +321,8 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
if (do_facenors_fix) {
faces_check_flip(*mesh, nos, mesh->face_normals());
}
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_loop_custom_set(vert_positions,
edges,
faces,
@ -361,8 +358,6 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
blender::MutableSpan<int> corner_edges,
const blender::OffsetIndices<int> faces)
{
using namespace blender;
const bke::AttributeAccessor attributes = mesh->attributes();
Object *ob_target = enmd->target;
const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
@ -431,8 +426,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
if (do_facenors_fix) {
faces_check_flip(*mesh, nos, mesh->face_normals());
}
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_loop_custom_set(positions,
edges,
faces,
@ -516,8 +511,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
clnors = static_cast<blender::short2 *>(
CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, corner_verts.size()));
loop_normals.reinitialize(corner_verts.size());
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&result->face_data, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_calc_loop(positions,
edges,
faces,
@ -526,7 +521,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
{},
result->vert_normals(),
result->face_normals(),
VArray<bool>::ForSpan(sharp_edges.span),
sharp_edges.span.data(),
sharp_faces,
clnors,
nullptr,

View File

@ -85,7 +85,7 @@ struct WeightedNormalData {
blender::OffsetIndices<int> faces;
blender::Span<blender::float3> face_normals;
blender::VArray<bool> sharp_faces;
const bool *sharp_faces;
const int *face_strength;
const MDeformVert *dvert;
@ -227,7 +227,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_to_face,
wn_data->vert_normals,
wn_data->face_normals,
blender::VArray<bool>::ForSpan(wn_data->sharp_edges),
wn_data->sharp_edges.data(),
wn_data->sharp_faces,
has_clnors ? clnors.data() : nullptr,
&lnors_spacearr,
@ -356,7 +356,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_to_face,
wn_data->vert_normals,
face_normals,
blender::VArray<bool>::ForSpan(wn_data->sharp_edges),
wn_data->sharp_edges.data(),
wn_data->sharp_faces,
has_clnors ? clnors.data() : nullptr,
nullptr,
@ -477,7 +477,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
using namespace blender;
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
Mesh *result;
result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
const int verts_num = result->totvert;
const blender::Span<blender::float3> positions = mesh->vert_positions();
@ -540,8 +541,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
wn_data.faces = faces;
wn_data.face_normals = mesh->face_normals();
wn_data.sharp_faces = *attributes.lookup_or_default<bool>("sharp_face", ATTR_DOMAIN_FACE, false);
wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named(
wn_data.sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->face_data, CD_PROP_BOOL, "sharp_face"));
wn_data.face_strength = static_cast<const int *>(CustomData_get_layer_named(
&result->face_data, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID));
wn_data.dvert = dvert;