GPv3: Material Selection node
Part of #113602. Pull Request: https://projects.blender.org/blender/blender/pulls/113827
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user