1
1

Compare commits

...

33 Commits

Author SHA1 Message Date
f35e15647b Changes based on Review by Hans Goudey (HooglyBoogly) 2021-10-10 22:15:52 +02:00
3e0f60d91e added missing comment 2021-10-04 23:51:06 +02:00
dc8bc59e2a Fixed problems with target_attribute was null 2021-10-04 23:47:05 +02:00
cec2aecd18 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
2021-10-04 22:01:25 +02:00
0d2d027df0 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
2021-10-02 00:18:17 +02:00
60f0364fb8 Mixing attributes when merging PointClouds. 2021-10-02 00:17:32 +02:00
07aa277973 working stage 2021-10-01 21:44:44 +02:00
8ffe20ffc9 Changes based on review by Hans Goudey (HooglyBoogly) 2021-09-30 18:03:54 +02:00
986bf72c44 Changes based on review by Hans Goudey (HooglyBoogly) 2021-09-30 10:01:47 +02:00
3a65475338 Changes based on review by Hans Goudey (HooglyBoogly) 2021-09-30 09:48:18 +02:00
621b2bd410 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance 2021-09-30 09:37:43 +02:00
569bbdec76 Changes based on review by Hans Goudey (HooglyBoogly) 2021-09-30 01:24:14 +02:00
63260db4a0 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	release/scripts/startup/nodeitems_builtins.py
#	source/blender/blenkernel/BKE_node.h
#	source/blender/blenkernel/intern/node.cc
#	source/blender/nodes/CMakeLists.txt
2021-09-30 00:28:18 +02:00
8a5fcaf8c6 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance 2021-09-26 21:47:05 +02:00
6a62487f83 Changes based on review by Hans Goudey (HooglyBoogly) 2021-09-26 21:46:36 +02:00
04ba70cc7f Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
#	source/blender/makesrna/intern/rna_nodetree.c
2021-09-25 00:10:27 +02:00
ac7163311d removed unneeded change in CMake file 2021-09-25 00:09:50 +02:00
0f20476116 merged master and updated the node to fields. 2021-09-24 23:59:31 +02:00
9eb502ee9c Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	release/scripts/startup/nodeitems_builtins.py
#	source/blender/blenkernel/BKE_node.h
#	source/blender/blenkernel/intern/node.cc
#	source/blender/makesrna/RNA_enum_types.h
#	source/blender/makesrna/intern/rna_nodetree.c
#	source/blender/modifiers/intern/MOD_weld.c
#	source/blender/nodes/NOD_geometry.h
#	source/blender/nodes/NOD_static_types.h
2021-09-24 00:56:34 +02:00
b60fa77678 Added missing line breaks at end of files. 2021-08-13 08:26:39 +02:00
4de8acc88d Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance 2021-08-13 08:19:37 +02:00
7df84749ad Changes based on review bv Hans Goudey (HooglyBoogly) 2021-08-13 08:18:58 +02:00
20d2c92119 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
#	source/blender/editors/asset/ED_asset_temp_id_consumer.h
2021-08-12 21:49:52 +02:00
239bf16cc7 Merge remote-tracking branch 'origin/soc-2021-porting-modifiers-to-nodes-merge-by-distance' into soc-2021-porting-modifiers-to-nodes-merge-by-distance 2021-07-24 22:48:52 +02:00
529913b2df - copied point cloud support from D10888 to this patch
- added support for selection with point cloud mode
2021-07-24 22:48:42 +02:00
2c6aeb6240 - copied point cloud support from D10888 to this patch
- added support for selection with point cloud mode
2021-07-24 22:47:58 +02:00
9503e34e99 Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/modifiers/intern/MOD_weld.c
2021-07-24 11:41:37 +02:00
096d6017cc Merge remote-tracking branch 'origin/soc-2021-porting-modifiers-to-nodes-merge-by-distance' into soc-2021-porting-modifiers-to-nodes-merge-by-distance 2021-07-23 21:07:07 +02:00
18f45f874c Geometry Nodes: Merge by Distance (Direct Modifier Port)
This patch is a direct port of the Weld modifier that moves the
common code to the geometry module.
I had made another version of a Merge by Distance Modifier (D10888), with an own implementation,
but I found that the original modifiers algorithm gives finer results.

Differential Revision: https://developer.blender.org/D12019
2021-07-23 21:00:07 +02:00
607119dd3f formatting 2021-07-23 12:03:45 +02:00
d777efbf5c Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-merge-by-distance
# Conflicts:
#	source/blender/blenkernel/BKE_node.h
2021-07-23 08:15:08 +02:00
7425af128f initial commit 2021-07-23 08:14:34 +02:00
9823ac0767 initial commit 2021-07-19 23:48:50 +02:00
22 changed files with 721 additions and 201 deletions

View File

@@ -557,6 +557,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeSeparateComponents"),
NodeItem("GeometryNodeSetPosition"),
NodeItem("GeometryNodeRealizeInstances"),
NodeItem("GeometryNodeMergeByDistance"),
]),
GeometryNodeCategory("GEO_INPUT", "Input", items=[
NodeItem("FunctionNodeLegacyRandomFloat", poll=geometry_nodes_legacy_poll),

View File

@@ -119,6 +119,7 @@ add_subdirectory(blenloader)
add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(simulation)
add_subdirectory(geometry)
add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)

View File

@@ -1515,6 +1515,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_SET_HANDLES 1100
#define GEO_NODE_POINTS_TO_VOLUME 1101
#define GEO_NODE_CURVE_HANDLE_TYPE_SELECTION 1102
#define GEO_NODE_MERGE_BY_DISTANCE 1103
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -5778,6 +5778,7 @@ static void registerGeometryNodes()
register_node_type_geo_material_assign();
register_node_type_geo_material_replace();
register_node_type_geo_material_selection();
register_node_type_geo_merge_by_distance();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();

View File

@@ -144,6 +144,14 @@ template<typename Key, typename Value> class MultiValueMap {
return map_.keys();
}
/**
* Return how many keys are currently stored in the Map.
*/
int64_t size() const
{
return std::distance(this->keys().begin(), this->keys().end());
}
/**
* NOTE: This signature will change when the implementation changes.
*/

View File

@@ -0,0 +1,47 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
../blenfont
../blenkernel
../blenlib
../blentranslation
../functions
../makesdna
../makesrna
../../../intern/guardedalloc
../makesdna/intern
${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
)
set(SRC
intern/mesh_merge_by_distance.cc
intern/pointcloud_merge_by_distance.cc
GEO_mesh_merge_by_distance.hh
GEO_pointcloud_merge_by_distance.hh
)
set(LIB
bf_blenkernel
bf_blenlib
)
blender_add_lib(bf_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@@ -0,0 +1,37 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup geo
*/
#include "BLI_span.hh"
namespace blender::geometry {
enum class WeldMode {
all = 0,
connected = 1,
};
struct Mesh *mesh_merge_by_distance(struct Mesh *mesh,
const Span<bool> mask,
const float merge_distance,
const WeldMode weld_mode);
} // namespace blender::geometry

View File

@@ -0,0 +1,29 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
/** \file
* \ingroup geo
*/
#include "BKE_geometry_set.hh"
namespace blender::geometry {
PointCloud *pointcloud_merge_by_distance(PointCloudComponent &pointcloud_component,
const float merge_threshold,
blender::Span<bool> selection);
}

View File

@@ -12,19 +12,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup modifiers
*
* Weld modifier: Remove doubles.
*/
/* TODOs:
* - Review weight and vertex color interpolation.;
*/
//#define USE_WELD_DEBUG
@@ -36,38 +23,21 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_kdtree.h"
#include "BLI_math.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#ifdef USE_BVHTREEKDOP
# include "BKE_bvhutils.h"
#endif
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "DEG_depsgraph.h"
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
#include "GEO_mesh_merge_by_distance.hh"
/* Indicates when the element was not computed. */
#define OUT_OF_CONTEXT (uint)(-1)
@@ -379,7 +349,7 @@ static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
uint wvert_len = 0;
WeldVert *wvert, *wv;
wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
wvert = (WeldVert *)MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
wv = &wvert[0];
uint *v_dest_iter = &r_vert_dest_map[0];
@@ -392,7 +362,7 @@ static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
}
}
*r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
*r_wvert = (WeldVert *)MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
*r_wvert_len = wvert_len;
}
@@ -425,7 +395,7 @@ static void weld_vert_groups_setup(const uint mvert_len,
}
}
struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
struct WeldGroup *wgroups = (WeldGroup *)MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
const WeldVert *wv = &wvert[0];
for (uint i = wvert_len; i--; wv++) {
@@ -442,7 +412,7 @@ static void weld_vert_groups_setup(const uint mvert_len,
BLI_assert(ofs == wvert_len);
uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
uint *groups_buffer = (uint *)MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
wv = &wvert[0];
for (uint i = wvert_len; i--; wv++) {
uint group_index = r_vert_groups_map[wv->vert_dest];
@@ -505,7 +475,7 @@ static void weld_edge_ctx_setup(const uint mvert_len,
}
if (link_len) {
uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
uint *link_edge_buffer = (uint *)MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
we = &r_wedge[0];
for (uint i = 0; i < wedge_len; i++, we++) {
@@ -596,11 +566,11 @@ static void weld_edge_ctx_alloc(const MEdge *medge,
uint *r_wedge_len)
{
/* Edge Context. */
uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
uint *edge_map = (uint *)MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
uint wedge_len = 0;
WeldEdge *wedge, *we;
wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
wedge = (WeldEdge *)MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
we = &wedge[0];
const MEdge *me = &medge[0];
@@ -626,7 +596,7 @@ static void weld_edge_ctx_alloc(const MEdge *medge,
}
}
*r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
*r_wedge = (WeldEdge *)MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
*r_wedge_len = wedge_len;
*r_edge_ctx_map = edge_map;
}
@@ -646,7 +616,7 @@ static void weld_edge_groups_setup(const uint medge_len,
struct WeldGroupEdge *wegroups, *wegrp_iter;
uint wgroups_len = wedge_len - edge_kill_len;
wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
wegroups = (WeldGroupEdge *)MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
wegrp_iter = &wegroups[0];
wgroups_len = 0;
@@ -693,7 +663,7 @@ static void weld_edge_groups_setup(const uint medge_len,
ofs += wegrp_iter->group.len;
}
uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
uint *groups_buffer = (uint *)MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
we = &wedge[0];
for (uint i = wedge_len; i--; we++) {
if (we->flag == ELEM_COLLAPSED) {
@@ -832,18 +802,18 @@ static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
WeldMesh *r_weld_mesh)
{
/* Loop/Poly Context. */
uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
uint *loop_map = (uint *)MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
uint *poly_map = (uint *)MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
uint wloop_len = 0;
uint wpoly_len = 0;
uint max_ctx_poly_len = 4;
WeldLoop *wloop, *wl;
wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
wloop = (WeldLoop *)MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
wl = &wloop[0];
WeldPoly *wpoly, *wp;
wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
wpoly = (WeldPoly *)MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
wp = &wpoly[0];
uint maybe_new_poly = 0;
@@ -910,14 +880,15 @@ static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
if (mpoly_len < (wpoly_len + maybe_new_poly)) {
WeldPoly *wpoly_tmp = wpoly;
wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
wpoly = (WeldPoly *)MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly),
__func__);
memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
MEM_freeN(wpoly_tmp);
}
WeldPoly *poly_new = &wpoly[wpoly_len];
r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
r_weld_mesh->wloop = (WeldLoop *)MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
r_weld_mesh->wpoly = wpoly;
r_weld_mesh->wpoly_new = poly_new;
r_weld_mesh->wloop_len = wloop_len;
@@ -1189,7 +1160,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
}
if (link_len) {
uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
uint *link_poly_buffer = (uint *)MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
wp = &wpoly[0];
for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
@@ -1331,8 +1302,8 @@ static void weld_mesh_context_create(const Mesh *mesh,
const uint mloop_len = mesh->totloop;
const uint mpoly_len = mesh->totpoly;
uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
uint *edge_dest_map = (uint *)MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
struct WeldGroup *v_links = (WeldGroup *)MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
WeldVert *wvert;
uint wvert_len;
@@ -1545,10 +1516,6 @@ static void customdata_weld(
/** \} */
/* -------------------------------------------------------------------- */
/** \name Weld Modifier Main
* \{ */
#ifdef USE_BVHTREEKDOP
struct WeldOverlapData {
const MVert *mvert;
@@ -1573,15 +1540,15 @@ struct WeldVertexCluster {
uint merged_verts;
};
static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
const ModifierEvalContext *UNUSED(ctx),
Mesh *mesh)
namespace blender::geometry {
Mesh *mesh_merge_by_distance(Mesh *mesh,
const Span<bool> mask,
const float merge_distance,
const WeldMode weld_mode)
{
Mesh *result = mesh;
BLI_bitmap *v_mask = NULL;
int v_mask_act = 0;
const MVert *mvert;
const MLoop *mloop;
const MPoly *mpoly, *mp;
@@ -1591,29 +1558,12 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
totvert = mesh->totvert;
/* Vertex Group. */
const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index != -1) {
MDeformVert *dvert, *dv;
dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (dvert) {
const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
dv = &dvert[0];
v_mask = BLI_BITMAP_NEW(totvert, __func__);
for (uint i = 0; i < totvert; i++, dv++) {
const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
if (found != invert_vgroup) {
BLI_BITMAP_ENABLE(v_mask, i);
v_mask_act++;
}
}
}
}
/* From the original index of the vertex.
* This indicates which vert it is or is going to be merged. */
uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
uint *vert_dest_map = (uint *)MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
uint vert_kill_len = 0;
if (wmd->mode == MOD_WELD_MODE_ALL)
if (weld_mode == WeldMode::all)
#ifdef USE_BVHTREEKDOP
{
/* Get overlap map. */
@@ -1624,7 +1574,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
false,
v_mask,
v_mask_act,
wmd->merge_dist / 2,
merge_distance / 2,
2,
6,
0,
@@ -1634,7 +1584,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
if (bvhtree) {
struct WeldOverlapData data;
data.mvert = mvert;
data.merge_dist_sq = square_f(wmd->merge_dist);
data.merge_dist_sq = square_f(merge_distance);
uint overlap_len;
BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree,
@@ -1695,9 +1645,9 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
#else
{
KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert);
KDTree_3d *tree = BLI_kdtree_3d_new(totvert);
for (uint i = 0; i < totvert; i++) {
if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) {
if (mask.size() == 0 || mask[i]) {
BLI_kdtree_3d_insert(tree, i, mvert[i].co);
}
vert_dest_map[i] = OUT_OF_CONTEXT;
@@ -1705,12 +1655,12 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
BLI_kdtree_3d_balance(tree);
vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
tree, wmd->merge_dist, false, (int *)vert_dest_map);
tree, merge_distance, false, (int *)vert_dest_map);
BLI_kdtree_3d_free(tree);
}
#endif
else {
BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED);
BLI_assert(weld_mode == WeldMode::connected);
MEdge *medge, *me;
@@ -1718,14 +1668,14 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
totvert = mesh->totvert;
totedge = mesh->totedge;
struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN(
struct WeldVertexCluster *vert_clusters = (WeldVertexCluster *)MEM_malloc_arrayN(
totvert, sizeof(*vert_clusters), __func__);
struct WeldVertexCluster *vc = &vert_clusters[0];
for (uint i = 0; i < totvert; i++, vc++) {
copy_v3_v3(vc->co, mvert[i].co);
vc->merged_verts = 0;
}
const float merge_dist_sq = square_f(wmd->merge_dist);
const float merge_dist_sq = square_f(merge_distance);
range_vn_u(vert_dest_map, totvert, 0);
@@ -1735,9 +1685,6 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
uint v1 = me->v1;
uint v2 = me->v2;
if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
continue;
}
while (v1 != vert_dest_map[v1]) {
v1 = vert_dest_map[v1];
}
@@ -1747,7 +1694,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
if (v1 == v2) {
continue;
}
if (v_mask && (!BLI_BITMAP_TEST(v_mask, v1) || !BLI_BITMAP_TEST(v_mask, v2))) {
if (mask.size() > 0 && (!mask[v1] || !mask[v2])) {
continue;
}
if (v1 > v2) {
@@ -1787,10 +1734,6 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
}
if (v_mask) {
MEM_freeN(v_mask);
}
if (vert_kill_len) {
WeldMesh weld_mesh;
weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
@@ -1987,93 +1930,4 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
MEM_freeN(vert_dest_map);
return result;
}
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
WeldModifierData *wmd = (WeldModifierData *)md;
return weldModifier_doWeld(wmd, ctx, mesh);
}
static void initData(ModifierData *md)
{
WeldModifierData *wmd = (WeldModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
WeldModifierData *wmd = (WeldModifierData *)md;
/* Ask for vertexgroups if we need them. */
if (wmd->defgrp_name[0] != '\0') {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
int weld_mode = RNA_enum_get(ptr, "mode");
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
if (weld_mode == MOD_WELD_MODE_CONNECTED) {
uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
}
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
}
ModifierTypeInfo modifierType_Weld = {
/* name */ "Weld",
/* structName */ "WeldModifierData",
/* structSize */ sizeof(WeldModifierData),
/* srna */ &RNA_WeldModifier,
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_AcceptsCVs,
/* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
/* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ NULL,
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
/* modifyMesh */ modifyMesh,
/* modifyHair */ NULL,
/* modifyGeometrySet */ NULL,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* freeRuntimeData */ NULL,
/* panelRegister */ panelRegister,
/* blendWrite */ NULL,
/* blendRead */ NULL,
};
/** \} */
} // namespace blender::geometry

View File

@@ -0,0 +1,157 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_pointcloud.h"
#include "BLI_array.hh"
#include "BLI_float3.hh"
#include "BLI_kdtree.h"
#include "BLI_multi_value_map.hh"
#include "BLI_span.hh"
#include "BLI_vector.hh"
#include "DNA_pointcloud_types.h"
#include "GEO_pointcloud_merge_by_distance.hh"
#include "FN_generic_span.hh"
using blender::MutableSpan;
namespace blender::geometry {
const static int POINT_NOT_MERGED = -1;
static KDTree_3d *build_kdtree(Span<float3> positions, Span<bool> selection)
{
BLI_assert(positions.size() == selection.size());
KDTree_3d *kdtree = BLI_kdtree_3d_new(selection.size());
for (const int i : positions.index_range()) {
if (selection[i]) {
BLI_kdtree_3d_insert(kdtree, i, positions[i]);
}
}
BLI_kdtree_3d_balance(kdtree);
return kdtree;
}
static void build_merge_map(Span<float3> positions,
MutableSpan<int> merge_map,
const float merge_threshold,
Span<bool> selection)
{
KDTree_3d *kdtree = build_kdtree(positions, selection);
for (int i : positions.index_range()) {
struct CallbackData {
int index;
MutableSpan<int> merge_map;
Span<bool> selection;
} callback_data = {i, merge_map, selection};
BLI_kdtree_3d_range_search_cb(
kdtree,
positions[i],
merge_threshold,
[](void *user_data,
int source_point_index,
const float *UNUSED(co),
float UNUSED(distance_squared)) {
CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
int target_point_index = callback_data.index;
if (source_point_index != target_point_index &&
callback_data.merge_map[source_point_index] == POINT_NOT_MERGED &&
callback_data.merge_map[target_point_index] == POINT_NOT_MERGED &&
callback_data.selection[source_point_index] &&
callback_data.selection[target_point_index]) {
callback_data.merge_map[source_point_index] = target_point_index;
}
return true;
},
&callback_data);
}
BLI_kdtree_3d_free(kdtree);
}
PointCloud *pointcloud_merge_by_distance(PointCloudComponent &pointcloud_component,
const float merge_threshold,
Span<bool> selection)
{
const PointCloud &src_pointcloud = *pointcloud_component.get_for_read();
Array<int> merge_map(src_pointcloud.totpoint, POINT_NOT_MERGED);
Span<float3> positions((const float3 *)src_pointcloud.co, src_pointcloud.totpoint);
build_merge_map(positions, merge_map, merge_threshold, selection);
MultiValueMap<int, int> copy_map;
for (const int i : merge_map.index_range()) {
if (merge_map[i] != POINT_NOT_MERGED) {
copy_map.add(merge_map[i], i);
}
}
PointCloud *pointcloud = BKE_pointcloud_new_nomain(copy_map.size());
PointCloudComponent dst_component;
dst_component.replace(pointcloud, GeometryOwnershipType::Editable);
pointcloud_component.attribute_foreach(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
fn::GVArrayPtr read_attribute = pointcloud_component.attribute_get_for_read(
attribute_id, meta_data.domain, meta_data.data_type);
if (!dst_component.attribute_exists(attribute_id) &&
!dst_component.attribute_try_create(
attribute_id, meta_data.domain, meta_data.data_type, AttributeInitDefault())) {
return true;
}
bke::OutputAttribute target_attribute = dst_component.attribute_try_get_for_output_only(
attribute_id, meta_data.domain, meta_data.data_type);
blender::attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
const fn::GVArray_Typed<T> src_span = read_attribute->typed<T>();
attribute_math::DefaultMixer<T> mixer(target_attribute.as_span<T>());
int index_new = 0;
for (const int index_old : copy_map.keys()) {
Span<int> merged_points = copy_map.lookup(index_old);
if (merged_points.size() > 0) {
float weight = 1.0f / (float(merged_points.size() + 1.0f));
mixer.mix_in(index_new, src_span[index_old], weight);
for (const int j : merged_points) {
mixer.mix_in(index_new, src_span[j], weight);
}
}
index_new++;
}
mixer.finalize();
});
target_attribute.save();
return true;
});
return pointcloud;
}
} // namespace blender::geometry

View File

@@ -27,7 +27,6 @@
#pragma once
#include "BLI_utildefines.h"
#include "dna_type_offsets.h"
#ifdef __cplusplus

View File

@@ -801,7 +801,7 @@
#define _DNA_DEFAULT_WeldModifierData \
{ \
.merge_dist = 0.001f, \
.mode = MOD_WELD_MODE_ALL, \
.mode = 0, \
.defgrp_name = "", \
}

View File

@@ -2051,12 +2051,6 @@ enum {
MOD_WELD_LOOSE_EDGES = (1 << 1),
};
/* #WeldModifierData.mode */
enum {
MOD_WELD_MODE_ALL = 0,
MOD_WELD_MODE_CONNECTED = 1,
};
typedef struct DataTransferModifierData {
ModifierData modifier;

View File

@@ -382,6 +382,7 @@ blender_include_dirs(
../../bmesh
../../depsgraph
../../draw
../../geometry
../../gpu
../../ikplugin
../../imbuf

View File

@@ -6172,17 +6172,17 @@ static void rna_def_modifier_laplaciandeform(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
const EnumPropertyItem rna_enum_modifier_weld_mode_items[] = {
{0, "ALL", 0, "All", "Full merge by distance"},
{1, "CONNECTED", 0, "Connected", "Only merge along the edges"},
{0, NULL, 0, NULL, NULL},
};
static void rna_def_modifier_weld(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem mode_items[] = {
{MOD_WELD_MODE_ALL, "ALL", 0, "All", "Full merge by distance"},
{MOD_WELD_MODE_CONNECTED, "CONNECTED", 0, "Connected", "Only merge along the edges"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "WeldModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier");
RNA_def_struct_sdna(srna, "WeldModifierData");
@@ -6191,7 +6191,7 @@ static void rna_def_modifier_weld(BlenderRNA *brna)
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_enum_items(prop, rna_enum_modifier_weld_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Mode defines the merge rule");
RNA_def_property_update(prop, 0, "rna_Modifier_update");

View File

@@ -10754,6 +10754,23 @@ static void def_geo_string_to_curves(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_geo_merge_by_distance(StructRNA *srna)
{
static const EnumPropertyItem rna_enum_geometry_nodes_weld_mode_items[] = {
{0, "ALL", 0, "All", "Full merge by distance."},
{1, "CONNECTED", 0, "Connected", "Only merge along the edges"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
prop = RNA_def_property(srna, "merge_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_geometry_nodes_weld_mode_items);
RNA_def_property_ui_text(
prop, "Mode", "Mode defines the merge rule. Only used when welding mesh data.");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)

View File

@@ -30,6 +30,7 @@ set(INC
../depsgraph
../editors/include
../functions
../geometry
../makesdna
../makesrna
../nodes
@@ -113,7 +114,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
intern/MOD_weld.c
intern/MOD_weld.cc
intern/MOD_wireframe.c
MOD_modifiertypes.h
@@ -129,6 +130,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
bf_geometry
)
if(WITH_ALEMBIC)

View File

@@ -0,0 +1,206 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 by the Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup modifiers
*
* Weld modifier: Remove doubles.
*/
/* TODOs:
* - Review weight and vertex color interpolation.;
*/
//#define USE_WELD_DEBUG
//#define USE_WELD_NORMALS
//#define USE_BVHTREEKDOP
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#ifdef USE_BVHTREEKDOP
# include "BKE_bvhutils.h"
#endif
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_modifier.h"
#include "BKE_screen.h"
#include "GEO_mesh_merge_by_distance.hh"
#include "UI_interface.h"
#include "UI_resources.h"
#include "RNA_access.h"
#include "MOD_ui_common.h"
using blender::geometry::WeldMode;
static WeldMode weld_mode_from_int(const short type)
{
switch (static_cast<WeldMode>(type)) {
case WeldMode::all:
return WeldMode::all;
case WeldMode::connected:
return WeldMode::connected;
}
BLI_assert_unreachable();
return WeldMode::all;
}
static int16_t weld_mode_to_int(const WeldMode weld_mode)
{
switch (weld_mode) {
case WeldMode::all:
return static_cast<int16_t>(WeldMode::all);
case WeldMode::connected:
return static_cast<int16_t>(WeldMode::connected);
}
BLI_assert_unreachable();
return static_cast<int16_t>(WeldMode::all);
}
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
{
WeldModifierData *wmd = (WeldModifierData *)md;
uint totvert = mesh->totvert;
blender::Array<bool> mask(totvert);
const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index != -1) {
MDeformVert *dvert, *dv;
dvert = (MDeformVert *)CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
if (dvert) {
const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
dv = &dvert[0];
for (uint i = 0; i < totvert; i++, dv++) {
const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
mask[i] = found != invert_vgroup;
}
}
}
else {
for (int i = 0; i < totvert; i++) {
mask[i] = true;
}
}
Mesh *result = blender::geometry::mesh_merge_by_distance(
mesh, mask, wmd->merge_dist, weld_mode_from_int(wmd->mode));
return result;
}
static void initData(ModifierData *md)
{
WeldModifierData *wmd = (WeldModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier));
MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeldModifierData), modifier);
}
static void requiredDataMask(Object *UNUSED(ob),
ModifierData *md,
CustomData_MeshMasks *r_cddata_masks)
{
WeldModifierData *wmd = (WeldModifierData *)md;
/* Ask for vertexgroups if we need them. */
if (wmd->defgrp_name[0] != '\0') {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
int weld_mode = RNA_enum_get(ptr, "mode");
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
if (weld_mode_from_int(weld_mode) == blender::geometry::WeldMode::connected) {
uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
}
modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
modifier_panel_end(layout, ptr);
}
static void panelRegister(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_Weld, panel_draw);
}
ModifierTypeInfo modifierType_Weld = {
/* name */ "Weld",
/* structName */ "WeldModifierData",
/* structSize */ sizeof(WeldModifierData),
/* srna */ &RNA_WeldModifier,
/* type */ eModifierTypeType_Constructive,
/* flags */
(ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
eModifierTypeFlag_AcceptsCVs),
/* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
/* copyData */ BKE_modifier_copydata_generic,
/* deformVerts */ nullptr,
/* deformMatrices */ nullptr,
/* deformVertsEM */ nullptr,
/* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
/* modifyHair */ nullptr,
/* modifyGeometrySet */ nullptr,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
/* freeData */ nullptr,
/* isDisabled */ nullptr,
/* updateDepsgraph */ nullptr,
/* dependsOnTime */ nullptr,
/* dependsOnNormals */ nullptr,
/* foreachIDLink */ nullptr,
/* foreachTexLink */ nullptr,
/* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
/* blendWrite */ nullptr,
/* blendRead */ nullptr,
};
/** \} */

View File

@@ -33,6 +33,7 @@ set(INC
../bmesh
../depsgraph
../functions
../geometry
../gpu
../imbuf
../makesdna
@@ -239,6 +240,7 @@ set(SRC
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
geometry/nodes/node_geo_mesh_subdivide.cc
geometry/nodes/node_geo_mesh_to_points.cc
geometry/nodes/node_geo_merge_by_distance.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_points_to_vertices.cc
geometry/nodes/node_geo_points_to_volume.cc
@@ -423,6 +425,7 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
bf_geometry
bf_intern_sky
)

View File

@@ -99,6 +99,7 @@ void register_node_type_geo_join_geometry(void);
void register_node_type_geo_material_assign(void);
void register_node_type_geo_material_replace(void);
void register_node_type_geo_material_selection(void);
void register_node_type_geo_merge_by_distance(void);
void register_node_type_geo_mesh_primitive_circle(void);
void register_node_type_geo_mesh_primitive_cone(void);
void register_node_type_geo_mesh_primitive_cube(void);

View File

@@ -357,6 +357,7 @@ DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry,
DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_REPLACE, 0, "MATERIAL_REPLACE", MaterialReplace, "Material Replace", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_SELECTION, 0, "MATERIAL_SELECTION", MaterialSelection, "Material Selection", "")
DefNode(GeometryNode, GEO_NODE_MERGE_BY_DISTANCE, def_geo_merge_by_distance, "MERGE_BY_DISTANCE", MergeByDistance, "Merge by Distance", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")

View File

@@ -0,0 +1,159 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BKE_pointcloud.h"
#include "BLI_float3.hh"
#include "BLI_span.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
#include "GEO_mesh_merge_by_distance.hh"
#include "GEO_pointcloud_merge_by_distance.hh"
#include "UI_interface.h"
#include "UI_resources.h"
#include "node_geometry_util.hh"
using blender::Array;
using blender::float3;
using blender::Span;
using blender::Vector;
using blender::geometry::WeldMode;
static WeldMode weld_mode_from_int(const short type)
{
switch (static_cast<WeldMode>(type)) {
case WeldMode::all:
return WeldMode::all;
case WeldMode::connected:
return WeldMode::connected;
}
BLI_assert_unreachable();
return WeldMode::all;
}
static int16_t weld_mode_to_int(const WeldMode weld_mode)
{
switch (weld_mode) {
case WeldMode::all:
return static_cast<int16_t>(WeldMode::all);
case WeldMode::connected:
return static_cast<int16_t>(WeldMode::connected);
}
BLI_assert_unreachable();
return static_cast<int16_t>(WeldMode::all);
}
namespace blender::nodes {
static void geo_node_merge_by_distance_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>("Geometry");
b.add_input<decl::Float>("Distance").min(0.0f).max(10000.0f).subtype(PROP_DISTANCE);
b.add_input<decl::Bool>("Selection").default_value(true).hide_value().supports_field();
b.add_output<decl::Geometry>("Geometry");
}
static void geo_node_merge_by_distance_layout(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
uiItemR(layout, ptr, "merge_mode", 0, "", ICON_NONE);
}
static void geo_merge_by_distance_init(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = weld_mode_to_int(WeldMode::all);
}
static void process_mesh(GeoNodeExecParams &params,
const WeldMode weld_mode,
const float distance,
GeometrySet &geometry_set)
{
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
Mesh *input_mesh = mesh_component.get_for_write();
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_POINT};
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
fn::FieldEvaluator selection_evaluator{field_context, input_mesh->totvert};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray_Span<bool> selection = selection_evaluator.get_evaluated<bool>(0);
Mesh *result = geometry::mesh_merge_by_distance(input_mesh, selection, distance, weld_mode);
if (result != input_mesh) {
geometry_set.replace_mesh(result);
}
}
static void process_pointcloud(GeoNodeExecParams &params,
const float distance,
GeometrySet &geometry_set)
{
PointCloudComponent &pointcloud_component =
geometry_set.get_component_for_write<PointCloudComponent>();
const PointCloud &pointcloud = *pointcloud_component.get_for_read();
GeometryComponentFieldContext field_context{pointcloud_component, ATTR_DOMAIN_POINT};
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
fn::FieldEvaluator selection_evaluator{field_context, pointcloud.totpoint};
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const VArray_Span<bool> selection = selection_evaluator.get_evaluated<bool>(0);
pointcloud_component.replace(
geometry::pointcloud_merge_by_distance(pointcloud_component, distance, selection));
}
static void geo_node_merge_by_distance_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const geometry::WeldMode weld_mode = weld_mode_from_int(params.node().custom1);
const float distance = params.extract_input<float>("Distance");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (geometry_set.has_mesh()) {
process_mesh(params, weld_mode, distance, geometry_set);
}
if (geometry_set.has_pointcloud()) {
process_pointcloud(params, distance, geometry_set);
}
});
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes
void register_node_type_geo_merge_by_distance()
{
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_MERGE_BY_DISTANCE, "Merge By Distance", NODE_CLASS_GEOMETRY, 0);
node_type_init(&ntype, blender::nodes::geo_merge_by_distance_init);
ntype.declare = blender::nodes::geo_node_merge_by_distance_declare;
ntype.geometry_node_execute = blender::nodes::geo_node_merge_by_distance_exec;
ntype.draw_buttons = blender::nodes::geo_node_merge_by_distance_layout;
nodeRegisterType(&ntype);
}