Point Cloud: Implement join operator

Similar to !134691.

Pull Request: https://projects.blender.org/blender/blender/pulls/134702
This commit is contained in:
Hans Goudey
2025-02-19 15:30:12 +01:00
committed by Hans Goudey
parent 5a6d2e1ce2
commit 0fd79c3613
4 changed files with 108 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ struct PointCloud;
struct rcti;
struct UndoType;
struct wmKeyConfig;
struct wmOperator;
struct wmOperatorType;
namespace blender::bke {
struct GSpanAttributeWriter;
@@ -143,6 +144,8 @@ void POINT_CLOUD_OT_attribute_set(wmOperatorType *ot);
void POINT_CLOUD_OT_duplicate(wmOperatorType *ot);
void POINT_CLOUD_OT_separate(wmOperatorType *ot);
int join_objects(bContext *C, wmOperator *op);
/** \} */
} // namespace blender::ed::point_cloud

View File

@@ -121,6 +121,7 @@
#include "ED_object.hh"
#include "ED_outliner.hh"
#include "ED_physics.hh"
#include "ED_point_cloud.hh"
#include "ED_render.hh"
#include "ED_screen.hh"
#include "ED_select_utils.hh"
@@ -4714,7 +4715,14 @@ static bool object_join_poll(bContext *C)
return false;
}
if (ELEM(ob->type, OB_MESH, OB_CURVES_LEGACY, OB_SURF, OB_ARMATURE, OB_GREASE_PENCIL, OB_CURVES))
if (ELEM(ob->type,
OB_MESH,
OB_CURVES_LEGACY,
OB_SURF,
OB_ARMATURE,
OB_CURVES,
OB_GREASE_PENCIL,
OB_POINTCLOUD))
{
return true;
}
@@ -4752,6 +4760,9 @@ static int object_join_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_ARMATURE) {
ret = ED_armature_join_objects_exec(C, op);
}
else if (ob->type == OB_POINTCLOUD) {
ret = point_cloud::join_objects(C, op);
}
else if (ob->type == OB_CURVES) {
ret = curves::join_objects(C, op);
}

View File

@@ -16,6 +16,7 @@ set(INC_SYS
set(SRC
intern/attribute_set.cc
intern/duplicate.cc
intern/join.cc
intern/point_cloud_edit.cc
intern/point_cloud_ops.cc
intern/point_cloud_selection.cc
@@ -28,6 +29,7 @@ set(LIB
PRIVATE bf::blenlib
PRIVATE bf::depsgraph
PRIVATE bf::dna
PRIVATE bf::geometry
PRIVATE bf::functions
PRIVATE bf::intern::clog
PRIVATE bf::intern::guardedalloc

View File

@@ -0,0 +1,91 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_map.hh"
#include "DNA_scene_types.h"
#include "BKE_context.hh"
#include "BKE_instances.hh"
#include "BKE_pointcloud.hh"
#include "BKE_report.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "ED_object.hh"
#include "ED_point_cloud.hh"
#include "GEO_realize_instances.hh"
namespace blender::ed::point_cloud {
int join_objects(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *active_object = CTX_data_active_object(C);
BLI_assert(active_object);
BLI_assert(active_object->type == OB_POINTCLOUD);
PointCloud &active_pointcloud = *static_cast<PointCloud *>(active_object->data);
const float4x4 &world_to_active = active_object->world_to_object();
Vector<Object *> objects{active_object};
bool active_object_selected = false;
CTX_DATA_BEGIN (C, Object *, object, selected_editable_objects) {
if (object == active_object) {
active_object_selected = true;
continue;
}
if (object->type != OB_POINTCLOUD) {
continue;
}
objects.append(object);
}
CTX_DATA_END;
if (!active_object_selected) {
BKE_report(op->reports, RPT_WARNING, "Active object is not a selected point cloud object");
return OPERATOR_CANCELLED;
}
bke::Instances instances;
instances.resize(objects.size());
MutableSpan<float4x4> transforms = instances.transforms_for_write();
MutableSpan<int> references = instances.reference_handles_for_write();
Map<const PointCloud *, int> reference_by_orig_points;
for (const int i : objects.index_range()) {
transforms[i] = world_to_active * objects[i]->object_to_world();
const PointCloud *orig_points = static_cast<const PointCloud *>(objects[i]->data);
references[i] = reference_by_orig_points.lookup_or_add_cb(orig_points, [&]() {
auto geometry = bke::GeometrySet::from_pointcloud(BKE_pointcloud_copy_for_eval(orig_points));
return instances.add_new_reference(std::move(geometry));
});
}
bke::GeometrySet realized_geometry = geometry::realize_instances(
bke::GeometrySet::from_instances(&instances, bke::GeometryOwnershipType::ReadOnly),
geometry::RealizeInstancesOptions());
PointCloud *realized_points =
realized_geometry.get_component_for_write<bke::PointCloudComponent>().release();
BKE_pointcloud_nomain_to_pointcloud(realized_points, &active_pointcloud);
for (Object *object : objects.as_span().drop_front(1)) {
object::base_free_and_unlink(bmain, scene, object);
}
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&active_object->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
return OPERATOR_FINISHED;
}
} // namespace blender::ed::point_cloud