diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index 957b99b986a..3613266ae52 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -3114,12 +3114,62 @@ static int mesh_to_grease_pencil_add_material(Main &bmain, return index; } +class FillColorRecord { + public: + float4 color; + StringRefNull name; + bool operator==(const FillColorRecord &other) const + { + return other.color == color && other.name == name; + } + uint64_t hash() const + { + return hash_string(name); + } +}; + +static VectorSet mesh_to_grease_pencil_get_material_list( + Object &ob_mesh, const Mesh &mesh, Array &material_remap) +{ + const short num_materials = mesh.totcol; + const FillColorRecord empty_fill = {float4(1.0f), DATA_("Empty Fill")}; + + /* This function will only be called when we want to create fills out of mesh faces, so always + * ensure that fills would have at least one material to be assigned to. */ + if (num_materials == 0) { + VectorSet fill_colors; + fill_colors.add(empty_fill); + material_remap.reinitialize(1); + material_remap[0] = 0; + return fill_colors; + } + + VectorSet fill_colors; + + material_remap.reinitialize(num_materials); + + for (const int material_i : IndexRange(num_materials)) { + const Material *mesh_material = BKE_object_material_get(&ob_mesh, material_i + 1); + if (!mesh_material) { + material_remap[material_i] = fill_colors.index_of_or_add(empty_fill); + continue; + } + const float4 fill_color = float4( + mesh_material->r, mesh_material->g, mesh_material->b, mesh_material->a); + const StringRefNull material_name = BKE_id_name(mesh_material->id); + const FillColorRecord record = {fill_color, material_name}; + material_remap[material_i] = fill_colors.index_of_or_add(record); + } + + return fill_colors; +} static void mesh_data_to_grease_pencil(const Mesh &mesh_eval, GreasePencil &grease_pencil, const int current_frame, const bool generate_faces, const float stroke_radius, - const float offset) + const float offset, + const Array &material_remap) { grease_pencil.flag |= GREASE_PENCIL_STROKE_ORDER_3D; @@ -3130,7 +3180,6 @@ static void mesh_data_to_grease_pencil(const Mesh &mesh_eval, bke::greasepencil::Layer &layer_line = grease_pencil.add_layer(DATA_("Lines")); bke::greasepencil::Drawing *drawing_line = grease_pencil.insert_frame(layer_line, current_frame); - constexpr int face_mat_index = 1; const Span mesh_positions = mesh_eval.vert_positions(); const Span vert_normals = mesh_eval.vert_normals(); const Span edges = mesh_eval.edges(); @@ -3153,12 +3202,20 @@ static void mesh_data_to_grease_pencil(const Mesh &mesh_eval, bke::SpanAttributeWriter stroke_materials_fill = curves_fill.attributes_for_write().lookup_or_add_for_write_span( "material_index", bke::AttrDomain::Curve); - curves_fill.fill_curve_types(CURVE_TYPE_POLY); + bke::AttributeAccessor mesh_attributes = mesh_eval.attributes(); + VArray mesh_materials = *mesh_attributes.lookup_or_default( + "material_index", bke::AttrDomain::Face, 0); + curves_fill.fill_curve_types(CURVE_TYPE_POLY); array_utils::gather(mesh_positions, corner_verts, positions_fill); array_utils::copy(faces_span, offsets_fill); cyclic_fill.fill(true); - stroke_materials_fill.span.fill(face_mat_index); + + MutableSpan material_span = stroke_materials_fill.span; + for (const int face_i : material_span.index_range()) { + /* Increase material index by 1 to accommodate the stroke material. */ + material_span[face_i] = material_remap[mesh_materials[face_i]] + 1; + } stroke_materials_fill.finish(); } @@ -3197,11 +3254,20 @@ static Object *convert_mesh_to_grease_pencil(Base &base, const float offset = RNA_float_get(info.op_props, "offset"); /* To be compatible with the thickness value prior to Grease Pencil v3. */ - const float stroke_radius = float(thickness) / 1000.0f; + const float stroke_radius = float(thickness) / 2 * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; - const Object *ob_eval = DEG_get_evaluated_object(info.depsgraph, ob); + Object *ob_eval = DEG_get_evaluated_object(info.depsgraph, ob); const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval); + VectorSet fill_colors; + Array material_remap; + if (generate_faces) { + fill_colors = mesh_to_grease_pencil_get_material_list(*ob_eval, *mesh_eval, material_remap); + } + + Mesh *newob_mesh = static_cast(newob->data); + BKE_id_material_clear(info.bmain, &newob_mesh->id); BKE_object_free_derived_caches(newob); BKE_object_free_modifiers(newob, 0); @@ -3213,18 +3279,26 @@ static Object *convert_mesh_to_grease_pencil(Base &base, * functions still depend on this value being coherent (The same value as * `GreasePencil::material_array_num`). */ - short *totcol = BKE_object_material_len_p(newob); - newob->totcol = *totcol; - newob->actcol = *totcol; + newob->totcol = 0; + newob->actcol = 0; mesh_to_grease_pencil_add_material( *info.bmain, *newob, DATA_("Stroke"), float4(0.0f, 0.0f, 0.0f, 1.0f), {}); + if (generate_faces) { - mesh_to_grease_pencil_add_material(*info.bmain, *newob, DATA_("Fill"), {}, float4(1.0f)); + for (const int fill_i : fill_colors.index_range()) { + const FillColorRecord &record = fill_colors[fill_i]; + mesh_to_grease_pencil_add_material(*info.bmain, *newob, record.name, {}, record.color); + } } - mesh_data_to_grease_pencil( - *mesh_eval, *grease_pencil, info.scene->r.cfra, generate_faces, stroke_radius, offset); + mesh_data_to_grease_pencil(*mesh_eval, + *grease_pencil, + info.scene->r.cfra, + generate_faces, + stroke_radius, + offset, + material_remap); return newob; }