Compare commits
33 Commits
temp-image
...
soc-2021-p
Author | SHA1 | Date | |
---|---|---|---|
f35e15647b | |||
3e0f60d91e | |||
dc8bc59e2a | |||
cec2aecd18 | |||
0d2d027df0 | |||
60f0364fb8 | |||
07aa277973 | |||
8ffe20ffc9 | |||
986bf72c44 | |||
3a65475338 | |||
621b2bd410 | |||
569bbdec76 | |||
63260db4a0 | |||
8a5fcaf8c6 | |||
6a62487f83 | |||
04ba70cc7f | |||
ac7163311d | |||
0f20476116 | |||
9eb502ee9c | |||
b60fa77678 | |||
4de8acc88d | |||
7df84749ad | |||
20d2c92119 | |||
239bf16cc7 | |||
529913b2df | |||
2c6aeb6240 | |||
9503e34e99 | |||
096d6017cc | |||
18f45f874c | |||
607119dd3f | |||
d777efbf5c | |||
7425af128f | |||
9823ac0767 |
@@ -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),
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -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();
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
47
source/blender/geometry/CMakeLists.txt
Normal file
47
source/blender/geometry/CMakeLists.txt
Normal 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}")
|
37
source/blender/geometry/GEO_mesh_merge_by_distance.hh
Normal file
37
source/blender/geometry/GEO_mesh_merge_by_distance.hh
Normal 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
|
29
source/blender/geometry/GEO_pointcloud_merge_by_distance.hh
Normal file
29
source/blender/geometry/GEO_pointcloud_merge_by_distance.hh
Normal 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);
|
||||
}
|
@@ -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
|
157
source/blender/geometry/intern/pointcloud_merge_by_distance.cc
Normal file
157
source/blender/geometry/intern/pointcloud_merge_by_distance.cc
Normal 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
|
@@ -27,7 +27,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "dna_type_offsets.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -801,7 +801,7 @@
|
||||
#define _DNA_DEFAULT_WeldModifierData \
|
||||
{ \
|
||||
.merge_dist = 0.001f, \
|
||||
.mode = MOD_WELD_MODE_ALL, \
|
||||
.mode = 0, \
|
||||
.defgrp_name = "", \
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -382,6 +382,7 @@ blender_include_dirs(
|
||||
../../bmesh
|
||||
../../depsgraph
|
||||
../../draw
|
||||
../../geometry
|
||||
../../gpu
|
||||
../../ikplugin
|
||||
../../imbuf
|
||||
|
@@ -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");
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
206
source/blender/modifiers/intern/MOD_weld.cc
Normal file
206
source/blender/modifiers/intern/MOD_weld.cc
Normal 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,
|
||||
};
|
||||
|
||||
/** \} */
|
@@ -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
|
||||
)
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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", "")
|
||||
|
@@ -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 ¶ms,
|
||||
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 ¶ms,
|
||||
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);
|
||||
}
|
Reference in New Issue
Block a user