Geometry Nodes: Integrate existing hair nodes and new hair dynamics assets

This change encapsulates various changes to the hair and dynamics assets.

Some of the more global changes:
- `hair_dynamics_assets.blend` renamed to `geometry_nodes_dynamics_assets.blend`
  (requires clearing the assets in the build folder to avoid having duplicate
  assets)
- `Remember Rest Geometry` renamed to `Capture Rest Geometry`
- `Capture Rest Geometry` moved into `geometry_nodes_essentials.blend`
- `Set Attachment Surface`
  - moved into `procedural_hair_node_assets.blend`
  - not used as a modifier asset anymore and is used inside of `Attach Hair
    Curves to Surface` which is the corresponding modifier with more
    functionality
  - uses a node-group internally to correct the rest data by object transform
    (that needs to be removed in case we solve this differently in the future)
  - `Set Rest/Animated Attachment Surface` are removed in favor of setting a
    single surface geometry, which contains its rest data in the geometry bundle
- Add descriptions to various interface sockets
- Simplify force closures
- Add default stage for custom effectors
- Support using surface set by b10d29bb36.
- Move `Experimental` to physics menu, use Animation by default.
- Combine two collider node groups into a unified one.

This changes come from the blender-assets repo.

Note, our manual test files need to be updated which isn't done as part of this
patch yet.

Co-authored-by: Jacques Lucke <jacques@blender.org> Pull Request:
https://projects.blender.org/blender/blender/pulls/159231
This commit is contained in:
Simon Thommes 2026-06-02 20:23:55 +02:00 • committed by Jacques Lucke
parent a1422f306e
commit e10a50f890
6 changed files with 106 additions and 9 deletions

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ec80ac28f84c90ee5c0032b2ac013e1c636c28b1fe6216b2b20013cdcae5db13
size 294756

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:985ba32cf4cd3399d4f919703458516d66edfc466d57c7a603a22f4795312f76
size 700471
oid sha256:ed2c4c21798cce71c29f5e3c5cc8a34a66eebecfe7c1d943fc07ed7d7b1d525b
size 696817

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:023aafdfcf89d2a8613485d9540b1a3444564f67bf88b1b5d5a3c1be3dcf1392
size 417038

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c560a2eff8a55fd14faa00863b400859bc1fb27fd01f67f9d3bc048dd123ebe5
size 2488590
oid sha256:36e8c6acce9af863c8d098a710edbd83e4a3ea2cbcfec0bb1d85f9f51c6c899c
size 2488918

View file

@ -69,6 +69,7 @@
#include "BKE_effect.h"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
#include "BKE_global.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_key.hh"
#include "BKE_lattice.hh"
@ -115,6 +116,8 @@
#include "WM_types.hh"
#include "ED_armature.hh"
#include "ED_asset.hh"
#include "ED_asset_menu_utils.hh"
#include "ED_curve.hh"
#include "ED_curves.hh"
#include "ED_gpencil_legacy.hh"
@ -132,6 +135,10 @@
#include "ED_transform.hh"
#include "ED_view3d.hh"
#include "MOD_nodes.hh"
#include "AS_asset_library.hh"
#include "ANIM_bone_collections.hh"
#include "UI_resources.hh"
@ -2320,6 +2327,67 @@ void OBJECT_OT_curves_random_add(wmOperatorType *ot)
add_generic_props(ot, false);
}
static NodesModifierData *add_essential_asset_modifier(bContext &C,
Object &object,
const StringRefNull path,
ReportList *reports)
{
Scene &scene = *CTX_data_scene(&C);
Main &bmain = *CTX_data_main(&C);
if (ID_IS_LINKED(&object)) {
return nullptr;
}
AssetWeakReference asset_weak_ref{};
asset_weak_ref.asset_library_type = ASSET_LIBRARY_ESSENTIALS;
asset_weak_ref.relative_asset_identifier = BLI_strdup(path.c_str());
if (G.background) {
/* For testing purposes, make sure assets are loaded (this make take too long to do
* automatically during user interaction). */
asset::list::storage_fetch_blocking(asset_system::all_library_reference(), C);
}
const asset_system::AssetRepresentation *asset_representation = asset::find_asset_from_weak_ref(
C, asset_weak_ref, reports);
if (!asset_representation) {
return nullptr;
}
ID *asset_id = asset::asset_local_id_ensure_imported(bmain, *asset_representation);
if (!asset_id) {
return nullptr;
}
if (GS(asset_id->name) != ID_NT) {
return nullptr;
}
bNodeTree *node_group = id_cast<bNodeTree *>(asset_id);
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(
modifier_add(reports, &bmain, &scene, &object, BKE_id_name(*asset_id), eModifierType_Nodes));
nmd->node_group = node_group;
id_us_plus(&node_group->id);
nmd->flag |= NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR;
BKE_modifier_unique_name(&object.modifiers, &nmd->modifier);
MOD_nodes_update_interface(&object, nmd);
DEG_id_tag_update(&object.id, ID_RECALC_GEOMETRY);
return nmd;
}
static bool has_capture_rest_geometry_modifier(const Object *object)
{
for (const ModifierData &md : object->modifiers) {
if (md.type != eModifierType_Nodes) {
continue;
}
const auto &nmd = reinterpret_cast<const NodesModifierData &>(md);
if (!nmd.node_group) {
continue;
}
if (StringRef(BKE_id_name(nmd.node_group->id)) == "Capture Rest Geometry") {
return true;
}
}
return false;
}
static wmOperatorStatus object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@ -2347,7 +2415,36 @@ static wmOperatorStatus object_curves_empty_hair_add_exec(bContext *C, wmOperato
curves_id->surface_uv_map = BLI_strdupn(uv_name.data(), uv_name.size());
}
if (!U.experimental.use_geometry_nodes_hair_dynamics) {
if (U.experimental.use_geometry_nodes_hair_dynamics) {
if (!has_capture_rest_geometry_modifier(surface_ob)) {
if (!add_essential_asset_modifier(
*C,
*surface_ob,
"nodes/geometry_nodes_essentials.blend/NodeTree/Capture Rest Geometry",
op->reports))
{
if (ID_IS_LINKED(surface_ob)) {
BKE_reportf(op->reports,
RPT_ERROR,
"Can't add \"Capture Rest Geometry\" modifier to linked \"%s\" object",
BKE_id_name(surface_ob->id));
}
else {
BKE_reportf(op->reports,
RPT_ERROR,
"Can't add \"Capture Rest Geometry\" modifier to \"%s\" object",
BKE_id_name(surface_ob->id));
}
}
}
NodesModifierData *dynamics_modifier = add_essential_asset_modifier(
*C,
*curves_ob,
"nodes/geometry_nodes_dynamics_assets.blend/NodeTree/Hair Dynamics",
op->reports);
dynamics_modifier->modifier.flag |= eModifierFlag_PinLast;
}
else {
ed::curves::ensure_surface_deformation_node_exists(*C, *curves_ob);
}

View file

@ -20,7 +20,7 @@ const FlatBundleTypePtr &MeshColliderBundle::get_bundle_type()
FlatBundleTypeBuilder b(MeshColliderBundle::name);
add_filter(b);
b.add<decl::Geometry>("geometry"_ustr);
b.add<decl::Float>("margin"_ustr).min(0.0f);
b.add<decl::Float>("margin"_ustr).min(0.0f).subtype(PROP_DISTANCE);
b.add<decl::Float>("friction"_ustr).min(0.0f);
b.add<decl::Float>("compliance"_ustr).min(0.0f);
b.add<decl::Bool>("deforming"_ustr).default_value(false);