diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index ddd6cc7a052..ad11f72984f 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -129,6 +129,15 @@ typedef struct Global { */ int debug; + /** + * When true, various geometry processing algorithms randomize the order of elements (e.g. + * vertices or edges) in the output. In many cases, we don't make guarantees about the exact + * order of elements. So if users depend on the indices with e.g. geometry nodes, their file can + * break in a different Blender version. Explicitly turning on randomization can help protect + * oneself against such breakages. + */ + bool randomize_geometry_element_order; + /** * Control behavior of file reading/writing. * diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index 3d339a5652d..f283c3bafe1 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC_SYS set(SRC geometry_attributes.cc geometry_ops.cc + geometry_randomization.cc node_group_operator.cc geometry_intern.hh diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh index e9ba987fa79..145396cfc35 100644 --- a/source/blender/editors/geometry/geometry_intern.hh +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -21,6 +21,7 @@ void GEOMETRY_OT_color_attribute_render_set(wmOperatorType *ot); void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot); void GEOMETRY_OT_attribute_convert(wmOperatorType *ot); void GEOMETRY_OT_color_attribute_convert(wmOperatorType *ot); +void GEOMETRY_OT_geometry_randomization(wmOperatorType *ot); void GEOMETRY_OT_execute_node_group(wmOperatorType *ot); diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc index 8285d9c30ca..85b9acb995a 100644 --- a/source/blender/editors/geometry/geometry_ops.cc +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -27,4 +27,5 @@ void ED_operatortypes_geometry() WM_operatortype_append(GEOMETRY_OT_attribute_convert); WM_operatortype_append(GEOMETRY_OT_color_attribute_convert); WM_operatortype_append(GEOMETRY_OT_execute_node_group); + WM_operatortype_append(GEOMETRY_OT_geometry_randomization); } diff --git a/source/blender/editors/geometry/geometry_randomization.cc b/source/blender/editors/geometry/geometry_randomization.cc new file mode 100644 index 00000000000..a5f683e7867 --- /dev/null +++ b/source/blender/editors/geometry/geometry_randomization.cc @@ -0,0 +1,58 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "WM_api.hh" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" + +#include "DEG_depsgraph.hh" + +#include "RNA_access.hh" +#include "RNA_define.hh" + +#include "geometry_intern.hh" + +namespace blender::ed::geometry { + +static int geometry_randomization_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + RNA_boolean_set(op->ptr, "value", G.randomize_geometry_element_order); + return WM_operator_props_popup(C, op, event); +} + +static int geometry_randomization_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + + G.randomize_geometry_element_order = RNA_boolean_get(op->ptr, "value"); + + LISTBASE_FOREACH (Object *, object, &bmain->objects) { + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + } + WM_event_add_notifier(C, NC_WINDOW, nullptr); + return OPERATOR_FINISHED; +} + +void GEOMETRY_OT_geometry_randomization(wmOperatorType *ot) +{ + ot->name = "Set Geometry Randomization"; + ot->idname = "GEOMETRY_OT_geometry_randomization"; + ot->description = "Toggle geometry randomization for debugging purposes"; + + ot->exec = geometry_randomization_exec; + ot->invoke = geometry_randomization_invoke; + ot->flag |= OPTYPE_UNDO | OPTYPE_REGISTER; + + RNA_def_boolean(ot->srna, + "value", + false, + "Value", + "Randomize the order of geometry elements (e.g. vertices or edges) after some " + "operations where there are no guarantees about the order. This avoids " + "accidentally depending on something that may change in the future"); +} + +} // namespace blender::ed::geometry diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index 9a17246fc9a..eda7767b8ab 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -30,6 +30,7 @@ set(SRC intern/mesh_to_volume.cc intern/point_merge_by_distance.cc intern/points_to_volume.cc + intern/randomize.cc intern/realize_instances.cc intern/resample_curves.cc intern/reverse_uv_sampler.cc @@ -54,6 +55,7 @@ set(SRC GEO_mesh_to_volume.hh GEO_point_merge_by_distance.hh GEO_points_to_volume.hh + GEO_randomize.hh GEO_realize_instances.hh GEO_resample_curves.hh GEO_reverse_uv_sampler.hh diff --git a/source/blender/geometry/GEO_randomize.hh b/source/blender/geometry/GEO_randomize.hh new file mode 100644 index 00000000000..4727b43b3a8 --- /dev/null +++ b/source/blender/geometry/GEO_randomize.hh @@ -0,0 +1,24 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +struct Mesh; +struct PointCloud; +namespace blender::bke { +class CurvesGeometry; +} + +namespace blender::geometry { + +bool use_debug_randomization(); + +void debug_randomize_vertex_order(Mesh *mesh); +void debug_randomize_edge_order(Mesh *mesh); +void debug_randomize_face_order(Mesh *mesh); +void debug_randomize_mesh_order(Mesh *mesh); +void debug_randomize_point_order(PointCloud *pointcloud); +void debug_randomize_curve_order(bke::CurvesGeometry *curves); + +}; // namespace blender::geometry diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc index 8098c466155..8d4dccf494a 100644 --- a/source/blender/geometry/intern/mesh_merge_by_distance.cc +++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc @@ -21,6 +21,7 @@ #include "BKE_mesh.hh" #include "GEO_mesh_merge_by_distance.hh" +#include "GEO_randomize.hh" #ifdef USE_WELD_DEBUG_TIME # include "BLI_timeit.hh" @@ -1680,6 +1681,8 @@ static Mesh *create_merged_mesh(const Mesh &mesh, BLI_assert(int(r_i) == result_nfaces); BLI_assert(loop_cur == result_nloops); + debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index b78b7922890..608ceccf936 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -12,6 +12,7 @@ #include "BKE_mesh_mapping.hh" #include "GEO_mesh_split_edges.hh" +#include "GEO_randomize.hh" namespace blender::geometry { @@ -591,6 +592,8 @@ void split_edges(Mesh &mesh, propagate_vert_attributes(mesh, vert_map); BKE_mesh_tag_edges_split(&mesh); + + debug_randomize_mesh_order(&mesh); } } // namespace blender::geometry diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index c501310590a..056ad06731f 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -17,6 +17,7 @@ #include "BKE_mesh.hh" #include "GEO_mesh_to_curve.hh" +#include "GEO_randomize.hh" namespace blender::geometry { @@ -74,6 +75,8 @@ BLI_NOINLINE bke::CurvesGeometry create_curve_from_vert_indices( return true; }); + debug_randomize_curve_order(&curves); + return curves; } diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc index 3d317706b97..01441669495 100644 --- a/source/blender/geometry/intern/point_merge_by_distance.cc +++ b/source/blender/geometry/intern/point_merge_by_distance.cc @@ -13,6 +13,7 @@ #include "BKE_pointcloud.h" #include "GEO_point_merge_by_distance.hh" +#include "GEO_randomize.hh" namespace blender::geometry { @@ -154,6 +155,8 @@ PointCloud *point_merge_by_distance(const PointCloud &src_points, }); } + debug_randomize_point_order(dst_pointcloud); + return dst_pointcloud; } diff --git a/source/blender/geometry/intern/randomize.cc b/source/blender/geometry/intern/randomize.cc new file mode 100644 index 00000000000..6f4bea740d2 --- /dev/null +++ b/source/blender/geometry/intern/randomize.cc @@ -0,0 +1,231 @@ +/* SPDX-FileCopyrightText: 2023 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include +#include + +#include "GEO_randomize.hh" + +#include "DNA_curves_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_pointcloud_types.h" + +#include "BKE_attribute.hh" +#include "BKE_attribute_math.hh" +#include "BKE_curves.hh" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.hh" + +#include "BLI_array.hh" + +namespace blender::geometry { + +static Array get_permutation(const int length, const int seed) +{ + Array data(length); + for (const int i : IndexRange(length)) { + data[i] = i; + } + std::shuffle(data.begin(), data.end(), std::default_random_engine(seed)); + return data; +} + +static Array invert_permutation(const Span permutation) +{ + Array data(permutation.size()); + for (const int i : permutation.index_range()) { + data[permutation[i]] = i; + } + return data; +} + +/** + * We can't use a fully random seed, because then the randomization wouldn't be deterministic, + * which is important to avoid causing issues when determinism is expected. Using a single constant + * seed is not ideal either, because then two geometries might be randomized equally or very + * similar. Ideally, the seed would be a hash of everything that feeds into the geometry processing + * algorithm before the randomization, but that's too expensive. Just use something simple but + * correct for now. + */ +static int seed_from_mesh(const Mesh &mesh) +{ + return mesh.totvert; +} + +static int seed_from_pointcloud(const PointCloud &pointcloud) +{ + return pointcloud.totpoint; +} + +static int seed_from_curves(const bke::CurvesGeometry &curves) +{ + return curves.point_num; +} + +static void reorder_customdata(CustomData &data, const Span new_by_old_map) +{ + CustomData new_data; + CustomData_copy_layout(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, new_by_old_map.size()); + + for (const int old_i : new_by_old_map.index_range()) { + const int new_i = new_by_old_map[old_i]; + CustomData_copy_data(&data, &new_data, old_i, new_i, 1); + } + CustomData_free(&data, new_by_old_map.size()); + data = new_data; +} + +void debug_randomize_vertex_order(Mesh *mesh) +{ + if (mesh == nullptr || !use_debug_randomization()) { + return; + } + + const int seed = seed_from_mesh(*mesh); + const Array new_by_old_map = get_permutation(mesh->totvert, seed); + + reorder_customdata(mesh->vert_data, new_by_old_map); + + for (int &v : mesh->edges_for_write().cast()) { + v = new_by_old_map[v]; + } + for (int &v : mesh->corner_verts_for_write()) { + v = new_by_old_map[v]; + } + + BKE_mesh_tag_topology_changed(mesh); +} + +void debug_randomize_edge_order(Mesh *mesh) +{ + if (mesh == nullptr || !use_debug_randomization()) { + return; + } + + const int seed = seed_from_mesh(*mesh); + const Array new_by_old_map = get_permutation(mesh->totedge, seed); + + reorder_customdata(mesh->edge_data, new_by_old_map); + + for (int &e : mesh->corner_edges_for_write()) { + e = new_by_old_map[e]; + } + + BKE_mesh_tag_topology_changed(mesh); +} + +static Array make_new_offset_indices(const OffsetIndices old_offsets, + const Span old_by_new_map) +{ + Array new_offsets(old_offsets.data().size()); + new_offsets[0] = 0; + for (const int new_i : old_offsets.index_range()) { + const int old_i = old_by_new_map[new_i]; + new_offsets[new_i + 1] = new_offsets[new_i] + old_offsets[old_i].size(); + } + return new_offsets; +} + +static void reorder_customdata_groups(CustomData &data, + const OffsetIndices old_offsets, + const OffsetIndices new_offsets, + const Span new_by_old_map) +{ + const int elements_num = new_offsets.total_size(); + const int groups_num = new_by_old_map.size(); + CustomData new_data; + CustomData_copy_layout(&data, &new_data, CD_MASK_ALL, CD_CONSTRUCT, elements_num); + for (const int old_i : IndexRange(groups_num)) { + const int new_i = new_by_old_map[old_i]; + const IndexRange old_range = old_offsets[old_i]; + const IndexRange new_range = new_offsets[new_i]; + BLI_assert(old_range.size() == new_range.size()); + CustomData_copy_data(&data, &new_data, old_range.start(), new_range.start(), old_range.size()); + } + CustomData_free(&data, elements_num); + data = new_data; +} + +void debug_randomize_face_order(Mesh *mesh) +{ + if (mesh == nullptr || !use_debug_randomization()) { + return; + } + + const int seed = seed_from_mesh(*mesh); + const Array new_by_old_map = get_permutation(mesh->faces_num, seed); + const Array old_by_new_map = invert_permutation(new_by_old_map); + + reorder_customdata(mesh->face_data, new_by_old_map); + + const OffsetIndices old_faces = mesh->faces(); + Array new_face_offsets = make_new_offset_indices(old_faces, old_by_new_map); + const OffsetIndices new_faces = new_face_offsets.as_span(); + + reorder_customdata_groups(mesh->loop_data, old_faces, new_faces, new_by_old_map); + + mesh->face_offsets_for_write().copy_from(new_face_offsets); + + BKE_mesh_tag_topology_changed(mesh); +} + +void debug_randomize_point_order(PointCloud *pointcloud) +{ + if (pointcloud == nullptr || !use_debug_randomization()) { + return; + } + + const int seed = seed_from_pointcloud(*pointcloud); + const Array new_by_old_map = get_permutation(pointcloud->totpoint, seed); + + reorder_customdata(pointcloud->pdata, new_by_old_map); + + pointcloud->tag_positions_changed(); + pointcloud->tag_radii_changed(); +} + +void debug_randomize_curve_order(bke::CurvesGeometry *curves) +{ + if (curves == nullptr || !use_debug_randomization()) { + return; + } + + const int seed = seed_from_curves(*curves); + const Array new_by_old_map = get_permutation(curves->curve_num, seed); + const Array old_by_new_map = invert_permutation(new_by_old_map); + + reorder_customdata(curves->curve_data, new_by_old_map); + + const OffsetIndices old_points_by_curve = curves->points_by_curve(); + Array new_curve_offsets = make_new_offset_indices(old_points_by_curve, old_by_new_map); + const OffsetIndices new_points_by_curve = new_curve_offsets.as_span(); + + reorder_customdata_groups( + curves->point_data, old_points_by_curve, new_points_by_curve, new_by_old_map); + + curves->offsets_for_write().copy_from(new_curve_offsets); + + curves->tag_topology_changed(); +} + +void debug_randomize_mesh_order(Mesh *mesh) +{ + if (mesh == nullptr || !use_debug_randomization()) { + return; + } + + debug_randomize_vertex_order(mesh); + debug_randomize_edge_order(mesh); + debug_randomize_face_order(mesh); +} + +bool use_debug_randomization() +{ + return G.randomize_geometry_element_order; +} + +} // namespace blender::geometry diff --git a/source/blender/modifiers/intern/MOD_bevel.cc b/source/blender/modifiers/intern/MOD_bevel.cc index 673505e7502..a777c10b44e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.cc +++ b/source/blender/modifiers/intern/MOD_bevel.cc @@ -39,6 +39,8 @@ #include "BLO_read_write.hh" +#include "GEO_randomize.hh" + #include "bmesh.h" #include "bmesh_tools.h" @@ -230,6 +232,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh BM_mesh_free(bm); + blender::geometry::debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index f4444c13a79..9a21d80fda5 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -51,6 +51,8 @@ #include "MEM_guardedalloc.h" +#include "GEO_randomize.hh" + #include "bmesh.h" #include "bmesh_tools.h" #include "tools/bmesh_boolean.h" @@ -501,6 +503,8 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, MutableSpan(result->mat, result->totcol).copy_from(materials); } + blender::geometry::debug_randomize_mesh_order(result); + return result; } #endif @@ -598,6 +602,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } + blender::geometry::debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/modifiers/intern/MOD_decimate.cc b/source/blender/modifiers/intern/MOD_decimate.cc index bde363094bd..f6aa43e6717 100644 --- a/source/blender/modifiers/intern/MOD_decimate.cc +++ b/source/blender/modifiers/intern/MOD_decimate.cc @@ -32,6 +32,8 @@ #include "DEG_depsgraph_query.hh" +#include "GEO_randomize.hh" + #include "bmesh.h" #include "bmesh_tools.h" @@ -207,6 +209,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh BM_mesh_free(bm); + blender::geometry::debug_randomize_mesh_order(result); + #ifdef USE_TIMEIT TIMEIT_END(decim); #endif diff --git a/source/blender/modifiers/intern/MOD_edgesplit.cc b/source/blender/modifiers/intern/MOD_edgesplit.cc index 69035f8e713..ebc9cc91e68 100644 --- a/source/blender/modifiers/intern/MOD_edgesplit.cc +++ b/source/blender/modifiers/intern/MOD_edgesplit.cc @@ -38,6 +38,8 @@ #include "MOD_modifiertypes.hh" #include "MOD_ui_common.hh" +#include "GEO_randomize.hh" + /* For edge split modifier node. */ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd); @@ -103,6 +105,8 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd) result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); BM_mesh_free(bm); + blender::geometry::debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/modifiers/intern/MOD_remesh.cc b/source/blender/modifiers/intern/MOD_remesh.cc index 4f0b4ae4b91..bd42cad66dd 100644 --- a/source/blender/modifiers/intern/MOD_remesh.cc +++ b/source/blender/modifiers/intern/MOD_remesh.cc @@ -36,6 +36,8 @@ #include "MOD_modifiertypes.hh" #include "MOD_ui_common.hh" +#include "GEO_randomize.hh" + #include #include @@ -198,6 +200,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, BKE_mesh_copy_parameters_for_eval(result, mesh); BKE_mesh_calc_edges(result, true, false); + + blender::geometry::debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index d67095395b3..441cd30466c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -13,6 +13,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_boolean_cc { @@ -145,6 +147,8 @@ static void node_geo_exec(GeoNodeExecParams params) selection.finish(); } + geometry::debug_randomize_mesh_order(result); + params.set_output("Mesh", GeometrySet::from_mesh(result)); #else params.error_message_add(NodeWarningType::Error, diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index d41e9d18655..d8dd36cfd6b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -10,6 +10,8 @@ #include "BKE_material.h" #include "BKE_mesh.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" #ifdef WITH_BULLET @@ -215,6 +217,9 @@ static void node_geo_exec(GeoNodeExecParams params) geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { Mesh *mesh = compute_hull(geometry_set); + if (mesh) { + geometry::debug_randomize_mesh_order(mesh); + } geometry_set.replace_mesh(mesh); geometry_set.keep_only_during_modify({GeometryComponent::Type::Mesh}); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index f5d82915e58..3711f1c5631 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -9,6 +9,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_curve_to_mesh_cc { @@ -37,11 +39,13 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, if (profile_curves == nullptr) { Mesh *mesh = bke::curve_to_wire_mesh(curves.geometry.wrap(), propagation_info); + geometry::debug_randomize_mesh_order(mesh); geometry_set.replace_mesh(mesh); } else { Mesh *mesh = bke::curve_to_mesh_sweep( curves.geometry.wrap(), profile_curves->geometry.wrap(), fill_caps, propagation_info); + geometry::debug_randomize_mesh_order(mesh); geometry_set.replace_mesh(mesh); } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index a47b9f9c026..b228caa13a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -22,6 +22,8 @@ #include "DEG_depsgraph_query.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_distribute_points_in_volume_cc { @@ -253,6 +255,8 @@ static void node_geo_exec(GeoNodeExecParams params) point_radii.span.fill(0.05f); point_radii.finish(); + geometry::debug_randomize_point_order(pointcloud); + geometry_set.replace_pointcloud(pointcloud); geometry_set.keep_only_during_modify({GeometryComponent::Type::PointCloud}); }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 2f3ed09dc9a..61a099a7afe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -24,6 +24,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_distribute_points_on_faces_cc { @@ -556,6 +558,8 @@ static void point_distribution_calculate(GeometrySet &geometry_set, const bool use_legacy_normal = params.node().custom2 != 0; compute_attribute_outputs( mesh, *pointcloud, bary_coords, looptri_indices, attribute_outputs, use_legacy_normal); + + geometry::debug_randomize_point_order(pointcloud); } static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index cf1ada8e1ab..1dc84d6713a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -12,6 +12,8 @@ #include "BKE_mesh.hh" #include "BKE_mesh_mapping.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_dual_mesh_cc { @@ -921,6 +923,7 @@ static void node_geo_exec(GeoNodeExecParams params) if (const Mesh *mesh = geometry_set.get_mesh()) { Mesh *new_mesh = calc_dual_mesh( *mesh, keep_boundaries, params.get_output_propagation_info("Dual Mesh")); + geometry::debug_randomize_mesh_order(new_mesh); geometry_set.replace_mesh(new_mesh); } }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 7111b493ba4..ca861f09e4e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -15,6 +15,8 @@ #include "BKE_mesh_mapping.hh" #include "BKE_mesh_runtime.hh" +#include "GEO_randomize.hh" + #include "NOD_rna_define.hh" #include "UI_interface.hh" @@ -1431,6 +1433,8 @@ static void node_geo_exec(GeoNodeExecParams params) break; } } + + geometry::debug_randomize_mesh_order(mesh); } }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc index 557d6b3660b..19e932f6e01 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_curves.cc @@ -14,6 +14,8 @@ #include "BKE_curves.hh" #include "BKE_curves_utils.hh" +#include "GEO_randomize.hh" + #include "DNA_pointcloud_types.h" namespace blender::nodes::node_geo_interpolate_curves_cc { @@ -759,6 +761,8 @@ static GeometrySet generate_interpolated_curves( child_curves_id->totcol = guide_curves_id.totcol; } + geometry::debug_randomize_curve_order(&child_curves); + return GeometrySet::from_curves(child_curves_id); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index 6ab30013c25..e1b1b974452 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -8,6 +8,8 @@ #include "BKE_material.h" #include "BKE_mesh.hh" +#include "GEO_randomize.hh" + #include "bmesh.h" #include "node_geometry_util.hh" @@ -107,6 +109,8 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, } attributes.remove("UVMap"); + geometry::debug_randomize_mesh_order(mesh); + mesh->bounds_set_eager(calculate_bounds_ico_sphere(radius, subdivisions)); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index 86becc348b1..1e3d0fc361c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -9,6 +9,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_mesh_subdivide_cc { @@ -48,6 +50,7 @@ static Mesh *simple_subdivide_mesh(const Mesh &mesh, const int level) BKE_subdiv_free(subdiv); + geometry::debug_randomize_mesh_order(result); return result; } #endif /* WITH_OPENSUBDIV */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc index 25836af3d8e..d24ff921842 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_curves.cc @@ -15,6 +15,8 @@ #include "BLI_sort.hh" #include "BLI_task.hh" +#include "GEO_randomize.hh" + #include "BKE_geometry_set.hh" namespace blender::nodes::node_geo_points_to_curves_cc { @@ -151,6 +153,8 @@ static Curves *curves_from_points(const PointCloud &points, {}, indices, curves.attributes_for_write()); + + geometry::debug_randomize_curve_order(&curves); return curves_id; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 503164eeb35..a4e939290d8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -20,6 +20,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_string_to_curves_cc { @@ -296,6 +298,8 @@ static Map create_curve_instances(GeoNodeExecParams ¶ms, bke::CurvesGeometry &curves = curves_id->geometry.wrap(); BKE_nurbList_free(&cu.nurb); + geometry::debug_randomize_curve_order(&curves); + float4x4 size_matrix = math::from_scale(float3(layout.final_font_size)); curves.transform(size_matrix); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index c0bd0a069a6..df05462c4ea 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -20,6 +20,8 @@ #include "NOD_rna_define.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_subdivision_surface_cc { @@ -159,6 +161,8 @@ static Mesh *mesh_subsurf_calc(const Mesh *mesh, BKE_id_free(nullptr, mesh_copy); } + geometry::debug_randomize_mesh_order(result); + return result; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index f5175d1b310..d876cdd445a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -15,6 +15,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + #include "node_geometry_util.hh" namespace blender::nodes::node_geo_triangulate_cc { @@ -67,6 +69,10 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh, /* Positions are not changed by the triangulation operation, so the bounds are the same. */ result->runtime->bounds_cache = mesh.runtime->bounds_cache; + /* Vertex order is not affected. */ + geometry::debug_randomize_edge_order(result); + geometry::debug_randomize_face_order(result); + return result; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 5aa751b949e..5adbaca360d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -26,6 +26,8 @@ #include "UI_interface.hh" #include "UI_resources.hh" +#include "GEO_randomize.hh" + namespace blender::nodes::node_geo_volume_to_mesh_cc { NODE_STORAGE_FUNCS(NodeGeometryVolumeToMesh) @@ -151,6 +153,8 @@ static Mesh *create_mesh_from_volume_grids(Span gri BKE_mesh_calc_edges(mesh, false, false); BKE_mesh_smooth_flag_set(mesh, false); + geometry::debug_randomize_mesh_order(mesh); + return mesh; }