diff options
Diffstat (limited to 'source/blender/simulation/intern')
5 files changed, 241 insertions, 39 deletions
diff --git a/source/blender/simulation/intern/particle_function.cc b/source/blender/simulation/intern/particle_function.cc index e0de68d9b29..935ef7983d9 100644 --- a/source/blender/simulation/intern/particle_function.cc +++ b/source/blender/simulation/intern/particle_function.cc @@ -50,12 +50,18 @@ ParticleFunction::ParticleFunction(const fn::MultiFunction *global_fn, } ParticleFunctionEvaluator::ParticleFunctionEvaluator( - const ParticleFunction &particle_fn, const ParticleChunkContext &particle_chunk_context) + const ParticleFunction &particle_fn, + const SimulationSolveContext &solve_context, + const ParticleChunkContext &particle_chunk_context) : particle_fn_(particle_fn), + solve_context_(solve_context), particle_chunk_context_(particle_chunk_context), mask_(particle_chunk_context_.index_mask()), outputs_(particle_fn_.output_types_.size(), nullptr) { + global_context_.add_global_context("PersistentDataHandleMap", &solve_context_.handle_map()); + per_particle_context_.add_global_context("PersistentDataHandleMap", + &solve_context_.handle_map()); } ParticleFunctionEvaluator::~ParticleFunctionEvaluator() diff --git a/source/blender/simulation/intern/particle_function.hh b/source/blender/simulation/intern/particle_function.hh index bbb40efb388..eec4a700383 100644 --- a/source/blender/simulation/intern/particle_function.hh +++ b/source/blender/simulation/intern/particle_function.hh @@ -60,6 +60,7 @@ class ParticleFunctionEvaluator { private: ResourceCollector resources_; const ParticleFunction &particle_fn_; + const SimulationSolveContext &solve_context_; const ParticleChunkContext &particle_chunk_context_; IndexMask mask_; fn::MFContextBuilder global_context_; @@ -69,6 +70,7 @@ class ParticleFunctionEvaluator { public: ParticleFunctionEvaluator(const ParticleFunction &particle_fn, + const SimulationSolveContext &solve_context, const ParticleChunkContext &particle_chunk_context); ~ParticleFunctionEvaluator(); diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc index d4161b06a00..4760063daca 100644 --- a/source/blender/simulation/intern/simulation_collect_influences.cc +++ b/source/blender/simulation/intern/simulation_collect_influences.cc @@ -50,31 +50,51 @@ static Span<const nodes::DNode *> get_particle_simulation_nodes(const nodes::Der return tree.nodes_by_type("SimulationNodeParticleSimulation"); } -static std::optional<Array<std::string>> compute_global_string_inputs( - nodes::MFNetworkTreeMap &network_map, Span<const fn::MFInputSocket *> sockets) +/* Returns true on success. */ +static bool compute_global_inputs(nodes::MFNetworkTreeMap &network_map, + ResourceCollector &resources, + Span<const fn::MFInputSocket *> sockets, + MutableSpan<fn::GMutableSpan> r_results) { int amount = sockets.size(); if (amount == 0) { - return Array<std::string>(); + return true; } if (network_map.network().have_dummy_or_unlinked_dependencies(sockets)) { - return {}; + return false; } fn::MFNetworkEvaluator network_fn{{}, sockets}; - fn::MFParamsBuilder params{network_fn, 1}; - - Array<std::string> strings(amount, NoInitialization()); - for (int i : IndexRange(amount)) { - params.add_uninitialized_single_output( - fn::GMutableSpan(fn::CPPType::get<std::string>(), strings.data() + i, 1)); + for (int param_index : network_fn.param_indices()) { + fn::MFParamType param_type = network_fn.param_type(param_index); + BLI_assert(param_type.category() == fn::MFParamType::Category::SingleOutput); /* For now. */ + const fn::CPPType &type = param_type.data_type().single_type(); + void *buffer = resources.linear_allocator().allocate(type.size(), type.alignment()); + resources.add(buffer, type.destruct_cb(), AT); + fn::GMutableSpan span{type, buffer, 1}; + r_results[param_index] = span; + params.add_uninitialized_single_output(span); } - fn::MFContextBuilder context; - network_fn.call({0}, params, context); + network_fn.call(IndexRange(1), params, context); + return true; +} +static std::optional<Array<std::string>> compute_global_string_inputs( + nodes::MFNetworkTreeMap &network_map, Span<const fn::MFInputSocket *> sockets) +{ + ResourceCollector local_resources; + Array<fn::GMutableSpan> computed_values(sockets.size(), NoInitialization()); + if (!compute_global_inputs(network_map, local_resources, sockets, computed_values)) { + return {}; + } + + Array<std::string> strings(sockets.size()); + for (int i : sockets.index_range()) { + strings[i] = std::move(computed_values[i].typed<std::string>()[0]); + } return strings; } @@ -203,7 +223,8 @@ class ParticleFunctionForce : public ParticleForce { IndexMask mask = context.particle_chunk().index_mask(); MutableSpan<float3> r_combined_force = context.force_dst(); - ParticleFunctionEvaluator evaluator{particle_fn_, context.particle_chunk()}; + ParticleFunctionEvaluator evaluator{ + particle_fn_, context.solve_context(), context.particle_chunk()}; evaluator.compute(); fn::VSpan<float3> forces = evaluator.get<float3>(0, "Force"); @@ -258,44 +279,120 @@ static void collect_forces(nodes::MFNetworkTreeMap &network_map, class MyBasicEmitter : public ParticleEmitter { private: - std::string name_; + Array<std::string> names_; + const fn::MultiFunction &inputs_fn_; + uint32_t seed_; public: - MyBasicEmitter(std::string name) : name_(std::move(name)) + MyBasicEmitter(Array<std::string> names, const fn::MultiFunction &inputs_fn, uint32_t seed) + : names_(std::move(names)), inputs_fn_(inputs_fn), seed_(seed) { } void emit(ParticleEmitterContext &context) const override { - ParticleAllocator *allocator = context.try_get_particle_allocator(name_); - if (allocator == nullptr) { + fn::MFContextBuilder mf_context; + mf_context.add_global_context("PersistentDataHandleMap", + &context.solve_context().handle_map()); + + fn::MFParamsBuilder mf_params{inputs_fn_, 1}; + bke::PersistentObjectHandle object_handle; + float rate; + mf_params.add_uninitialized_single_output(&object_handle); + mf_params.add_uninitialized_single_output(&rate); + inputs_fn_.call(IndexRange(1), mf_params, mf_context); + + const Object *object = context.solve_context().handle_map().lookup(object_handle); + if (object == nullptr) { return; } - fn::MutableAttributesRef attributes = allocator->allocate(10); - RandomNumberGenerator rng{(uint32_t)context.simulation_time_interval().start() ^ - (uint32_t)DefaultHash<std::string>{}(name_)}; + Vector<float3> new_positions; + Vector<float3> new_velocities; + Vector<float> new_birth_times; + + float start_time = context.simulation_time_interval().start(); + RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed_}; + + int amount = rate * 10; + for (int i : IndexRange(amount)) { + UNUSED_VARS(i); + new_positions.append(rng.get_unit_float3() * 0.3 + float3(object->loc)); + new_velocities.append(rng.get_unit_float3()); + new_birth_times.append(context.simulation_time_interval().start()); + } + + for (StringRef name : names_) { + ParticleAllocator *allocator = context.try_get_particle_allocator(name); + if (allocator == nullptr) { + return; + } - MutableSpan<float3> positions = attributes.get<float3>("Position"); - MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); - MutableSpan<float> birth_times = attributes.get<float>("Birth Time"); + fn::MutableAttributesRef attributes = allocator->allocate(amount); - for (int i : IndexRange(attributes.size())) { - positions[i] = rng.get_unit_float3(); - velocities[i] = rng.get_unit_float3(); - birth_times[i] = context.simulation_time_interval().start(); + initialized_copy_n(new_positions.data(), amount, attributes.get<float3>("Position").data()); + initialized_copy_n(new_velocities.data(), amount, attributes.get<float3>("Velocity").data()); + initialized_copy_n( + new_birth_times.data(), amount, attributes.get<float>("Birth Time").data()); } } }; +static Vector<const nodes::DNode *> find_linked_particle_simulations( + const nodes::DOutputSocket &output_socket) +{ + Vector<const nodes::DNode *> simulation_nodes; + for (const nodes::DInputSocket *target_socket : output_socket.linked_sockets()) { + if (target_socket->node().idname() == "SimulationNodeParticleSimulation") { + simulation_nodes.append(&target_socket->node()); + } + } + return simulation_nodes; +} + +static ParticleEmitter *create_particle_emitter(const nodes::DNode &dnode, + ResourceCollector &resources, + nodes::MFNetworkTreeMap &network_map) +{ + Vector<const nodes::DNode *> simulation_dnodes = find_linked_particle_simulations( + dnode.output(0)); + if (simulation_dnodes.size() == 0) { + return nullptr; + } + + Array<std::string> names{simulation_dnodes.size()}; + for (int i : simulation_dnodes.index_range()) { + names[i] = dnode_to_path(*simulation_dnodes[i]); + } + + Array<const fn::MFInputSocket *> input_sockets{dnode.inputs().size()}; + for (int i : input_sockets.index_range()) { + input_sockets[i] = &network_map.lookup_dummy(dnode.input(i)); + } + + if (network_map.network().have_dummy_or_unlinked_dependencies(input_sockets)) { + return nullptr; + } + + fn::MultiFunction &inputs_fn = resources.construct<fn::MFNetworkEvaluator>( + AT, Span<const fn::MFOutputSocket *>(), input_sockets.as_span()); + + uint32_t seed = DefaultHash<std::string>{}(dnode_to_path(dnode)); + ParticleEmitter &emitter = resources.construct<MyBasicEmitter>( + AT, std::move(names), inputs_fn, seed); + return &emitter; +} + static void collect_emitters(nodes::MFNetworkTreeMap &network_map, ResourceCollector &resources, SimulationInfluences &r_influences) { - for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) { - std::string name = dnode_to_path(*dnode); - ParticleEmitter &emitter = resources.construct<MyBasicEmitter>(AT, name); - r_influences.particle_emitters.append(&emitter); + for (const nodes::DNode *dnode : + network_map.tree().nodes_by_type("SimulationNodeParticleMeshEmitter")) { + ParticleEmitter *emitter = create_particle_emitter(*dnode, resources, network_map); + if (emitter != nullptr) { + r_influences.particle_emitters.append(emitter); + } } } @@ -316,6 +413,23 @@ static void prepare_particle_attribute_builders(nodes::MFNetworkTreeMap &network } } +static void find_used_data_blocks(const nodes::DerivedNodeTree &tree, + SimulationInfluences &r_influences) +{ + const bNodeSocketType *socktype = nodeSocketTypeFind("NodeSocketObject"); + BLI_assert(socktype != nullptr); + + for (const nodes::DInputSocket *dsocket : tree.input_sockets()) { + const bNodeSocket *bsocket = dsocket->bsocket(); + if (bsocket->typeinfo == socktype) { + Object *value = ((const bNodeSocketValueObject *)bsocket->default_value)->value; + if (value != nullptr) { + r_influences.used_data_blocks.add(&value->id); + } + } + } +} + void collect_simulation_influences(Simulation &simulation, ResourceCollector &resources, SimulationInfluences &r_influences, @@ -343,6 +457,8 @@ void collect_simulation_influences(Simulation &simulation, for (const nodes::DNode *dnode : get_particle_simulation_nodes(tree)) { r_states_info.particle_simulation_names.add(dnode_to_path(*dnode)); } + + find_used_data_blocks(tree, r_influences); } } // namespace blender::sim diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc index f542d6ab2c8..158c50957df 100644 --- a/source/blender/simulation/intern/simulation_solver.cc +++ b/source/blender/simulation/intern/simulation_solver.cc @@ -17,8 +17,11 @@ #include "simulation_solver.hh" #include "BKE_customdata.h" +#include "BKE_lib_id.h" +#include "BKE_persistent_data_handle.hh" #include "BLI_rand.hh" +#include "BLI_set.hh" namespace blender::sim { @@ -243,6 +246,53 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta state.next_particle_id += allocator.total_allocated(); } +static void update_persistent_data_handles(Simulation &simulation, + const VectorSet<ID *> &used_data_blocks) +{ + Set<ID *> contained_ids; + Set<int> used_handles; + + /* Remove handles that have been invalidated. */ + LISTBASE_FOREACH_MUTABLE ( + PersistentDataHandleItem *, handle_item, &simulation.persistent_data_handles) { + if (handle_item->id == nullptr) { + BLI_remlink(&simulation.persistent_data_handles, handle_item); + continue; + } + if (!used_data_blocks.contains(handle_item->id)) { + id_us_min(handle_item->id); + BLI_remlink(&simulation.persistent_data_handles, handle_item); + MEM_freeN(handle_item); + continue; + } + contained_ids.add_new(handle_item->id); + used_handles.add_new(handle_item->handle); + } + + /* Add new handles that are not in the list yet. */ + int next_handle = 0; + for (ID *id : used_data_blocks) { + if (contained_ids.contains(id)) { + continue; + } + + /* Find the next available handle. */ + while (used_handles.contains(next_handle)) { + next_handle++; + } + used_handles.add_new(next_handle); + + PersistentDataHandleItem *handle_item = (PersistentDataHandleItem *)MEM_callocN( + sizeof(*handle_item), AT); + /* Cannot store const pointers in DNA. */ + id_us_plus(id); + handle_item->id = id; + handle_item->handle = next_handle; + + BLI_addtail(&simulation.persistent_data_handles, handle_item); + } +} + void initialize_simulation_states(Simulation &simulation, Depsgraph &UNUSED(depsgraph), const SimulationInfluences &UNUSED(influences)) @@ -255,11 +305,18 @@ void solve_simulation_time_step(Simulation &simulation, const SimulationInfluences &influences, float time_step) { - SimulationSolveContext solve_context{ - simulation, - depsgraph, - influences, - TimeInterval(simulation.current_simulation_time, time_step)}; + update_persistent_data_handles(simulation, influences.used_data_blocks); + + bke::PersistentDataHandleMap handle_map; + LISTBASE_FOREACH (PersistentDataHandleItem *, handle, &simulation.persistent_data_handles) { + handle_map.add(handle->handle, *handle->id); + } + + SimulationSolveContext solve_context{simulation, + depsgraph, + influences, + TimeInterval(simulation.current_simulation_time, time_step), + handle_map}; TimeInterval simulation_time_interval{simulation.current_simulation_time, time_step}; Vector<SimulationState *> simulation_states{simulation.states}; diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh index b5e42b53846..1d1b9935661 100644 --- a/source/blender/simulation/intern/simulation_solver.hh +++ b/source/blender/simulation/intern/simulation_solver.hh @@ -24,6 +24,8 @@ #include "FN_attributes_ref.hh" +#include "BKE_persistent_data_handle.hh" + #include "particle_allocator.hh" #include "time_interval.hh" @@ -50,6 +52,7 @@ struct SimulationInfluences { Map<std::string, Vector<const ParticleForce *>> particle_forces; Map<std::string, fn::AttributesInfoBuilder *> particle_attributes_builder; Vector<const ParticleEmitter *> particle_emitters; + VectorSet<ID *> used_data_blocks; }; class SimulationSolveContext { @@ -58,16 +61,19 @@ class SimulationSolveContext { Depsgraph &depsgraph_; const SimulationInfluences &influences_; TimeInterval solve_interval_; + const bke::PersistentDataHandleMap &id_handle_map_; public: SimulationSolveContext(Simulation &simulation, Depsgraph &depsgraph, const SimulationInfluences &influences, - TimeInterval solve_interval) + TimeInterval solve_interval, + const bke::PersistentDataHandleMap &handle_map) : simulation_(simulation), depsgraph_(depsgraph), influences_(influences), - solve_interval_(solve_interval) + solve_interval_(solve_interval), + id_handle_map_(handle_map) { } @@ -80,6 +86,11 @@ class SimulationSolveContext { { return influences_; } + + const bke::PersistentDataHandleMap &handle_map() const + { + return id_handle_map_; + } }; class ParticleAllocators { @@ -147,6 +158,11 @@ class ParticleEmitterContext { { } + SimulationSolveContext &solve_context() + { + return solve_context_; + } + ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name) { return particle_allocators_.try_get_allocator(particle_simulation_name); @@ -174,6 +190,11 @@ class ParticleForceContext { { } + SimulationSolveContext &solve_context() + { + return solve_context_; + } + const ParticleChunkContext &particle_chunk() const { return particle_chunk_context_; |