Geometry Nodes: show used named attributes in modifier

This adds a new subpanel to the geometry nodes modifier which is just
used to display information about used attributes.

* A new panel is used because adding this information anywhere else
  clutters the ui too much imo.
* The general layout is similar to that in the tooltip. I found it to be more
  trouble than it's worth to share this code.

Possible future improvements:
* Don't show the panel if there are no used named attributes.
* Add some heuristics to determine which named attributes the user does
  not have to care about because they are only used in the node group
  and don't affect anything else.

Differential Revision: https://developer.blender.org/D14701
This commit is contained in:
Jacques Lucke 2022-04-21 15:10:07 +02:00
parent ed971a19fa
commit 0178e694b7
Notes: blender-bot 2023-02-14 10:14:07 +01:00
Referenced by issue #96273, Named attribute modifier panel visualization
1 changed files with 72 additions and 0 deletions

View File

@ -119,6 +119,7 @@ using blender::threading::EnumerableThreadSpecific;
using namespace blender::fn::multi_function_types;
using namespace blender::nodes::derived_node_tree_types;
using geo_log::GeometryAttributeInfo;
using geo_log::NamedAttributeUsage;
static void initData(ModifierData *md)
{
@ -1619,6 +1620,71 @@ static void output_attribute_panel_draw(const bContext *C, Panel *panel)
}
}
static void used_attributes_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
if (nmd->runtime_eval_log == nullptr) {
return;
}
const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
Map<std::string, NamedAttributeUsage> usage_by_attribute;
log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
used_attribute.usage) |= used_attribute.usage;
}
});
if (usage_by_attribute.is_empty()) {
uiItemL(layout, IFACE_("No named attributes used"), ICON_INFO);
return;
}
Vector<std::pair<StringRefNull, NamedAttributeUsage>> sorted_used_attribute;
for (auto &&item : usage_by_attribute.items()) {
sorted_used_attribute.append({item.key, item.value});
}
std::sort(sorted_used_attribute.begin(), sorted_used_attribute.end());
for (const auto &pair : sorted_used_attribute) {
const StringRefNull attribute_name = pair.first;
const NamedAttributeUsage usage = pair.second;
/* #uiLayoutRowWithHeading doesn't seem to work in this case. */
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
std::stringstream ss;
Vector<std::string> usages;
if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
usages.append(TIP_("Read"));
}
if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
usages.append(TIP_("Write"));
}
if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
usages.append(TIP_("Remove"));
}
for (const int i : usages.index_range()) {
ss << usages[i];
if (i < usages.size() - 1) {
ss << ", ";
}
}
uiLayout *row = uiLayoutRow(split, false);
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
uiLayoutSetActive(row, false);
uiItemL(row, ss.str().c_str(), ICON_NONE);
row = uiLayoutRow(split, false);
uiItemL(row, attribute_name.c_str(), ICON_NONE);
}
}
static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
@ -1628,6 +1694,12 @@ static void panelRegister(ARegionType *region_type)
nullptr,
output_attribute_panel_draw,
panel_type);
modifier_subpanel_register(region_type,
"used_attributes",
N_("Used Attributes"),
nullptr,
used_attributes_panel_draw,
panel_type);
}
static void blendWrite(BlendWriter *writer, const ModifierData *md)