Fix T99191: Boolean modifier creates invalid material indices
This changes the boolean modifier material index handling to be
consistent with the mesh boolean geometry nodes, which was
last changed in 1a6d0ec71c. The issues was that the
material maps were retrieved at the object level, which doesn't
really make sense because the boolean is a geometry-level
operation. It was also confusing and prone to incorrect behavior
because it's more complex to retrieve information from two places.
Differential Revision: https://developer.blender.org/D15365
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
#include "BLI_math_geom.h"
|
#include "BLI_math_geom.h"
|
||||||
#include "BLI_math_matrix.h"
|
#include "BLI_math_matrix.h"
|
||||||
#include "BLI_vector.hh"
|
#include "BLI_vector.hh"
|
||||||
|
#include "BLI_vector_set.hh"
|
||||||
|
|
||||||
#include "BLT_translation.h"
|
#include "BLT_translation.h"
|
||||||
|
|
||||||
@@ -62,7 +63,11 @@
|
|||||||
|
|
||||||
using blender::Array;
|
using blender::Array;
|
||||||
using blender::float4x4;
|
using blender::float4x4;
|
||||||
|
using blender::IndexRange;
|
||||||
|
using blender::MutableSpan;
|
||||||
|
using blender::Span;
|
||||||
using blender::Vector;
|
using blender::Vector;
|
||||||
|
using blender::VectorSet;
|
||||||
|
|
||||||
static void initData(ModifierData *md)
|
static void initData(ModifierData *md)
|
||||||
{
|
{
|
||||||
@@ -375,19 +380,20 @@ static void BMD_mesh_intersection(BMesh *bm,
|
|||||||
|
|
||||||
#ifdef WITH_GMP
|
#ifdef WITH_GMP
|
||||||
|
|
||||||
/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
|
/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result
|
||||||
* If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
|
* geometry. The material is added to the result geometry if it doesn't already use it.
|
||||||
* or to zero if there aren't enough slots in the destination.
|
|
||||||
* Caller owns the returned array. */
|
* Caller owns the returned array. */
|
||||||
static Array<short> get_material_remap(Object *dest_ob, Object *src_ob)
|
static Array<short> get_material_remap(const Mesh &mesh, VectorSet<Material *> &materials)
|
||||||
{
|
{
|
||||||
int n = src_ob->totcol;
|
if (mesh.totcol == 0) {
|
||||||
if (n <= 0) {
|
/* Necessary for faces using the default material when there are no material slots. */
|
||||||
n = 1;
|
return Array<short>({materials.index_of_or_add(nullptr)});
|
||||||
}
|
}
|
||||||
Array<short> remap(n);
|
Array<short> map(mesh.totcol);
|
||||||
BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
|
for (const int i : IndexRange(mesh.totcol)) {
|
||||||
return remap;
|
map[i] = materials.index_of_or_add(mesh.mat[i]);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
||||||
@@ -396,6 +402,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||||||
{
|
{
|
||||||
Vector<const Mesh *> meshes;
|
Vector<const Mesh *> meshes;
|
||||||
Vector<float4x4 *> obmats;
|
Vector<float4x4 *> obmats;
|
||||||
|
|
||||||
|
VectorSet<Material *> materials;
|
||||||
Vector<Array<short>> material_remaps;
|
Vector<Array<short>> material_remaps;
|
||||||
|
|
||||||
# ifdef DEBUG_TIME
|
# ifdef DEBUG_TIME
|
||||||
@@ -409,6 +417,14 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||||||
meshes.append(mesh);
|
meshes.append(mesh);
|
||||||
obmats.append((float4x4 *)&ctx->object->obmat);
|
obmats.append((float4x4 *)&ctx->object->obmat);
|
||||||
material_remaps.append({});
|
material_remaps.append({});
|
||||||
|
if (mesh->totcol == 0) {
|
||||||
|
/* Necessary for faces using the default material when there are no material slots. */
|
||||||
|
materials.add(nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
materials.add_multiple({mesh->mat, mesh->totcol});
|
||||||
|
}
|
||||||
|
|
||||||
if (bmd->flag & eBooleanModifierFlag_Object) {
|
if (bmd->flag & eBooleanModifierFlag_Object) {
|
||||||
Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
|
Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
|
||||||
if (!mesh_operand) {
|
if (!mesh_operand) {
|
||||||
@@ -417,7 +433,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||||||
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
|
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
|
||||||
meshes.append(mesh_operand);
|
meshes.append(mesh_operand);
|
||||||
obmats.append((float4x4 *)&bmd->object->obmat);
|
obmats.append((float4x4 *)&bmd->object->obmat);
|
||||||
material_remaps.append(get_material_remap(ctx->object, bmd->object));
|
material_remaps.append(get_material_remap(*mesh_operand, materials));
|
||||||
}
|
}
|
||||||
else if (bmd->flag & eBooleanModifierFlag_Collection) {
|
else if (bmd->flag & eBooleanModifierFlag_Collection) {
|
||||||
Collection *collection = bmd->collection;
|
Collection *collection = bmd->collection;
|
||||||
@@ -432,7 +448,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||||||
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
|
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
|
||||||
meshes.append(collection_mesh);
|
meshes.append(collection_mesh);
|
||||||
obmats.append((float4x4 *)&ob->obmat);
|
obmats.append((float4x4 *)&ob->obmat);
|
||||||
material_remaps.append(get_material_remap(ctx->object, ob));
|
material_remaps.append(get_material_remap(*collection_mesh, materials));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
|
||||||
@@ -441,13 +457,18 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
|
|||||||
|
|
||||||
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
|
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
|
||||||
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
|
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
|
||||||
return blender::meshintersect::direct_mesh_boolean(meshes,
|
Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
|
||||||
obmats,
|
obmats,
|
||||||
*(float4x4 *)&ctx->object->obmat,
|
*(float4x4 *)&ctx->object->obmat,
|
||||||
material_remaps,
|
material_remaps,
|
||||||
use_self,
|
use_self,
|
||||||
hole_tolerant,
|
hole_tolerant,
|
||||||
bmd->operation);
|
bmd->operation);
|
||||||
|
MEM_SAFE_FREE(result->mat);
|
||||||
|
result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
|
||||||
|
result->totcol = materials.size();
|
||||||
|
MutableSpan(result->mat, result->totcol).copy_from(materials);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user