Fix T103663: Set material node can fail for single material

Caused by f1c0249f34, which filled the wrong value.
I have noticed several problems:
- Using a full array as single result.
- Checking single material index for 0. If we have a list of all slots,
  then we must check this in the list.
- The result was filled false. Simple fix.
- Fixed problem with incorrect recording by mask indices, not polygons.
    - Added domain specifics to names to avoid confusion.

Differential Revision: https://developer.blender.org/D16926
This commit is contained in:
Iliya Katueshenock 2023-01-06 09:34:03 -05:00 committed by Hans Goudey
parent 2752a88478
commit 3b37538975
Notes: blender-bot 2023-02-14 06:32:27 +01:00
Referenced by issue #103663, Regression: The Material Selection node in Geometry Nodes doesn't select any geometry
1 changed files with 24 additions and 26 deletions

View File

@ -20,35 +20,40 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>(N_("Selection")).field_source();
}
static void select_mesh_by_material(const Mesh &mesh,
const Material *material,
const IndexMask mask,
MutableSpan<bool> r_selection)
static VArray<bool> select_mesh_faces_by_material(const Mesh &mesh,
const Material *material,
const IndexMask face_mask)
{
BLI_assert(mesh.totpoly >= r_selection.size());
Vector<int> slots;
for (const int i : IndexRange(mesh.totcol)) {
if (mesh.mat[i] == material) {
slots.append(i);
for (const int slot_i : IndexRange(mesh.totcol)) {
if (mesh.mat[slot_i] == material) {
slots.append(slot_i);
}
}
if (slots.is_empty()) {
return VArray<bool>::ForSingle(false, mesh.totpoly);
}
const AttributeAccessor attributes = mesh.attributes();
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
if (material != nullptr && material_indices.is_single() &&
material_indices.get_internal_single() == 0) {
r_selection.fill_indices(mask, false);
return;
if (material_indices.is_single()) {
const int slot_i = material_indices.get_internal_single();
return VArray<bool>::ForSingle(slots.contains(slot_i), mesh.totpoly);
}
const VArraySpan<int> material_indices_span(material_indices);
threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
Array<bool> face_selection(face_mask.min_array_size());
threading::parallel_for(face_mask.index_range(), 1024, [&](IndexRange range) {
for (const int i : range) {
const int face_index = mask[i];
r_selection[i] = slots.contains(material_indices_span[face_index]);
const int face_index = face_mask[i];
const int slot_i = material_indices_span[face_index];
face_selection[face_index] = slots.contains(slot_i);
}
});
return VArray<bool>::ForContainer(std::move(face_selection));
}
class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
@ -72,19 +77,12 @@ class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
if (mesh == nullptr) {
return {};
}
const eAttrDomain domain = context.domain();
if (domain == ATTR_DOMAIN_FACE) {
Array<bool> selection(mask.min_array_size());
select_mesh_by_material(*mesh, material_, mask, selection);
return VArray<bool>::ForContainer(std::move(selection));
}
const IndexMask domain_mask = (domain == ATTR_DOMAIN_FACE) ? mask : IndexMask(mesh->totpoly);
Array<bool> selection(mesh->totpoly);
select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
return mesh->attributes().adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
return nullptr;
VArray<bool> selection = select_mesh_faces_by_material(*mesh, material_, domain_mask);
return mesh->attributes().adapt_domain<bool>(std::move(selection), ATTR_DOMAIN_FACE, domain);
}
uint64_t hash() const override