GPv3: Material Selection node

Part of #113602.

Pull Request: https://projects.blender.org/blender/blender/pulls/113827
This commit is contained in:
Dalai Felinto
2023-10-17 19:52:46 +02:00
parent ed124d23d1
commit 42f71c9dca

View File

@@ -12,6 +12,8 @@
#include "BLI_task.hh"
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_material.h"
namespace blender::nodes::node_geo_material_selection_cc {
@@ -22,37 +24,37 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Bool>("Selection").field_source();
}
static VArray<bool> select_mesh_faces_by_material(const Mesh &mesh,
const Material *material,
const IndexMask &face_mask)
static VArray<bool> select_by_material(const Span<Material *> materials,
const Material *material,
const AttributeAccessor &attributes,
const eAttrDomain domain,
const IndexMask &domain_mask)
{
const int domain_size = attributes.domain_size(domain);
Vector<int> slots;
for (const int slot_i : IndexRange(mesh.totcol)) {
if (mesh.mat[slot_i] == material) {
for (const int slot_i : IndexRange(materials.size())) {
if (materials[slot_i] == material) {
slots.append(slot_i);
}
}
if (slots.is_empty()) {
return VArray<bool>::ForSingle(false, mesh.faces_num);
return VArray<bool>::ForSingle(false, domain_size);
}
const AttributeAccessor attributes = mesh.attributes();
const VArray<int> material_indices = *attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
"material_index", domain, 0);
if (material_indices.is_single()) {
const int slot_i = material_indices.get_internal_single();
return VArray<bool>::ForSingle(slots.contains(slot_i), mesh.faces_num);
return VArray<bool>::ForSingle(slots.contains(slot_i), domain_size);
}
const VArraySpan<int> material_indices_span(material_indices);
Array<bool> face_selection(face_mask.min_array_size());
face_mask.foreach_index_optimized<int>(GrainSize(1024), [&](const int face_index) {
const int slot_i = material_indices_span[face_index];
face_selection[face_index] = slots.contains(slot_i);
Array<bool> domain_selection(domain_mask.min_array_size());
domain_mask.foreach_index_optimized<int>(GrainSize(1024), [&](const int domain_index) {
const int slot_i = material_indices_span[domain_index];
domain_selection[domain_index] = slots.contains(slot_i);
});
return VArray<bool>::ForContainer(std::move(face_selection));
return VArray<bool>::ForContainer(std::move(domain_selection));
}
class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
@@ -69,19 +71,54 @@ class MaterialSelectionFieldInput final : public bke::GeometryFieldInput {
GVArray get_varray_for_context(const bke::GeometryFieldContext &context,
const IndexMask &mask) const final
{
if (context.type() != GeometryComponent::Type::Mesh) {
return {};
}
const Mesh *mesh = context.mesh();
if (mesh == nullptr) {
if (!ELEM(
context.type(), GeometryComponent::Type::Mesh, GeometryComponent::Type::GreasePencil))
{
return {};
}
const eAttrDomain domain = context.domain();
const IndexMask domain_mask = (domain == ATTR_DOMAIN_FACE) ? mask : IndexMask(mesh->faces_num);
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);
switch (context.type()) {
case (GeometryComponent::Type::Mesh): {
const Mesh *mesh = context.mesh();
if (mesh == nullptr) {
return {};
}
const eAttrDomain domain = context.domain();
const IndexMask domain_mask = (domain == ATTR_DOMAIN_FACE) ? mask :
IndexMask(mesh->faces_num);
const AttributeAccessor attributes = mesh->attributes();
VArray<bool> selection = select_by_material(
{mesh->mat, mesh->totcol}, material_, attributes, domain, domain_mask);
return mesh->attributes().adapt_domain<bool>(
std::move(selection), ATTR_DOMAIN_FACE, domain);
}
case (GeometryComponent::Type::GreasePencil): {
const bke::CurvesGeometry *curves = context.curves_or_strokes();
if (curves == nullptr) {
return {};
}
const eAttrDomain domain = context.domain();
const IndexMask domain_mask = (domain == ATTR_DOMAIN_CURVE) ?
mask :
IndexMask(curves->curves_num());
const AttributeAccessor attributes = curves->attributes();
const VArray<int> material_indices = *attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_CURVE, 0);
const GreasePencil &grease_pencil = *context.grease_pencil();
VArray<bool> selection = select_by_material(
{grease_pencil.material_array, grease_pencil.material_array_num},
material_,
attributes,
domain,
domain_mask);
return curves->attributes().adapt_domain<bool>(
std::move(selection), ATTR_DOMAIN_CURVE, domain);
}
default:
BLI_assert_unreachable();
break;
}
return {};
}
uint64_t hash() const override