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:
Hans Goudey 2022-07-05 10:44:56 -05:00
parent bcfabdc09d
commit a2d59b2dac
Notes: blender-bot 2023-02-14 02:30:11 +01:00
Referenced by commit 7540842ca7, Fix T99592: Exact Boolean: Skip empty materials, add index-based option
Referenced by commit bbb389589a, Fix T99592: Exact Boolean: Skip empty materials, add index-based option
Referenced by issue #102596, Viewport display of multiple Dupli-Collections when different draw-types are used : wireframe might disappear (only selected are garuanteed to draw)
Referenced by issue #100690, Blender 3.2.1 Recent Files List Not Updating
Referenced by issue #100416, Crashed out when start rendering
Referenced by issue #100369, Blender 3.2.1 - Particles - Particles generate differently on Linux vs Windows
Referenced by issue #100156, Grease Pencil crashing Blender 3.2.0 / 3.2.1.
Referenced by issue #100079, Encoding with DNxHD fails due to bad parameters
Referenced by issue #99970, Difference in rendering alpha between CUDA/Optix and HIP
Referenced by issue #99813, Bevel is problematic in some cases
Referenced by issue #99746, Blender 3.2.1 Very Slow Startup on Ubuntu 22.04
Referenced by issue #99720, Blender Crash when i switch the viewport shading to material preview or render
Referenced by issue #99592, Regression: Boolean Difference modifier - material of hole created by hidden object different for fast and exact
Referenced by issue #99568, Exception during start programm.
Referenced by issue #99507, Camera Background image is appearing greyish in 3D Viewport
Referenced by issue #99191, Regression: Blender crashes when texture painting (caused by boolean modifers)
Referenced by issue #99015, Segmentation fault while texture painting
Referenced by issue #98661, 3.2: Potential candidates for corrective releases
1 changed files with 40 additions and 19 deletions

View File

@ -14,6 +14,7 @@
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "BLT_translation.h"
@ -62,7 +63,11 @@
using blender::Array;
using blender::float4x4;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
using blender::Vector;
using blender::VectorSet;
static void initData(ModifierData *md)
{
@ -375,19 +380,20 @@ static void BMD_mesh_intersection(BMesh *bm,
#ifdef WITH_GMP
/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
* If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
* or to zero if there aren't enough slots in the destination.
/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result
* geometry. The material is added to the result geometry if it doesn't already use it.
* 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 (n <= 0) {
n = 1;
if (mesh.totcol == 0) {
/* Necessary for faces using the default material when there are no material slots. */
return Array<short>({materials.index_of_or_add(nullptr)});
}
Array<short> remap(n);
BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
return remap;
Array<short> map(mesh.totcol);
for (const int i : IndexRange(mesh.totcol)) {
map[i] = materials.index_of_or_add(mesh.mat[i]);
}
return map;
}
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
@ -396,6 +402,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
{
Vector<const Mesh *> meshes;
Vector<float4x4 *> obmats;
VectorSet<Material *> materials;
Vector<Array<short>> material_remaps;
# ifdef DEBUG_TIME
@ -409,6 +417,14 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
meshes.append(mesh);
obmats.append((float4x4 *)&ctx->object->obmat);
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) {
Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
if (!mesh_operand) {
@ -417,7 +433,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
meshes.append(mesh_operand);
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) {
Collection *collection = bmd->collection;
@ -432,7 +448,7 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
meshes.append(collection_mesh);
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;
@ -441,13 +457,18 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
return blender::meshintersect::direct_mesh_boolean(meshes,
obmats,
*(float4x4 *)&ctx->object->obmat,
material_remaps,
use_self,
hole_tolerant,
bmd->operation);
Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
obmats,
*(float4x4 *)&ctx->object->obmat,
material_remaps,
use_self,
hole_tolerant,
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