Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/simulation')
-rw-r--r--source/blender/simulation/CMakeLists.txt3
-rw-r--r--source/blender/simulation/SIM_simulation_update.hh4
-rw-r--r--source/blender/simulation/intern/particle_allocator.cc2
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.cc344
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.hh49
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc137
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.hh2
-rw-r--r--source/blender/simulation/intern/simulation_solver.cc127
-rw-r--r--source/blender/simulation/intern/simulation_solver.hh246
-rw-r--r--source/blender/simulation/intern/simulation_solver_influences.hh265
-rw-r--r--source/blender/simulation/intern/simulation_update.cc95
-rw-r--r--source/blender/simulation/intern/time_interval.hh2
12 files changed, 831 insertions, 445 deletions
diff --git a/source/blender/simulation/CMakeLists.txt b/source/blender/simulation/CMakeLists.txt
index 243b056db74..6466a6e67d4 100644
--- a/source/blender/simulation/CMakeLists.txt
+++ b/source/blender/simulation/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
intern/implicit_eigen.cpp
intern/particle_allocator.cc
intern/particle_function.cc
+ intern/particle_mesh_emitter.cc
intern/simulation_collect_influences.cc
intern/simulation_solver.cc
intern/simulation_update.cc
@@ -52,7 +53,9 @@ set(SRC
intern/implicit.h
intern/particle_allocator.hh
intern/particle_function.hh
+ intern/particle_mesh_emitter.hh
intern/simulation_collect_influences.hh
+ intern/simulation_solver_influences.hh
intern/simulation_solver.hh
intern/time_interval.hh
diff --git a/source/blender/simulation/SIM_simulation_update.hh b/source/blender/simulation/SIM_simulation_update.hh
index 40b62bfb58a..efdfde8a4de 100644
--- a/source/blender/simulation/SIM_simulation_update.hh
+++ b/source/blender/simulation/SIM_simulation_update.hh
@@ -27,6 +27,8 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
Scene *scene_cow,
Simulation *simulation_cow);
-}
+bool update_simulation_dependencies(Simulation *simulation);
+
+} // namespace blender::sim
#endif /* __SIM_SIMULATION_UPDATE_HH__ */
diff --git a/source/blender/simulation/intern/particle_allocator.cc b/source/blender/simulation/intern/particle_allocator.cc
index eb1e998e63a..5ff5909f506 100644
--- a/source/blender/simulation/intern/particle_allocator.cc
+++ b/source/blender/simulation/intern/particle_allocator.cc
@@ -68,7 +68,7 @@ fn::MutableAttributesRef ParticleAllocator::allocate(int size)
}
}
else {
- type.fill_uninitialized(info.default_of(i), attributes.get(i).buffer(), size);
+ type.fill_uninitialized(info.default_of(i), attributes.get(i).data(), size);
}
}
return attributes;
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.cc b/source/blender/simulation/intern/particle_mesh_emitter.cc
new file mode 100644
index 00000000000..15a6bffa884
--- /dev/null
+++ b/source/blender/simulation/intern/particle_mesh_emitter.cc
@@ -0,0 +1,344 @@
+/*
+ * 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 "particle_mesh_emitter.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_rand.hh"
+#include "BLI_vector_adaptor.hh"
+
+#include "BKE_mesh_runtime.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+namespace blender::sim {
+
+ParticleMeshEmitter::~ParticleMeshEmitter() = default;
+
+struct EmitterSettings {
+ Object *object;
+ float rate;
+};
+
+static BLI_NOINLINE void compute_birth_times(float rate,
+ TimeInterval emit_interval,
+ ParticleMeshEmitterSimulationState &state,
+ Vector<float> &r_birth_times)
+{
+ const float time_between_particles = 1.0f / rate;
+ int counter = 0;
+ while (true) {
+ counter++;
+ const float time_offset = counter * time_between_particles;
+ const float birth_time = state.last_birth_time + time_offset;
+ if (birth_time > emit_interval.end()) {
+ break;
+ }
+ if (birth_time <= emit_interval.start()) {
+ continue;
+ }
+ r_birth_times.append(birth_time);
+ }
+}
+
+static BLI_NOINLINE Span<MLoopTri> get_mesh_triangles(Mesh &mesh)
+{
+ const MLoopTri *triangles = BKE_mesh_runtime_looptri_ensure(&mesh);
+ int amount = BKE_mesh_runtime_looptri_len(&mesh);
+ return Span(triangles, amount);
+}
+
+static BLI_NOINLINE void compute_triangle_areas(Mesh &mesh,
+ Span<MLoopTri> triangles,
+ MutableSpan<float> r_areas)
+{
+ assert_same_size(triangles, r_areas);
+
+ for (int i : triangles.index_range()) {
+ const MLoopTri &tri = triangles[i];
+
+ const float3 v1 = mesh.mvert[mesh.mloop[tri.tri[0]].v].co;
+ const float3 v2 = mesh.mvert[mesh.mloop[tri.tri[1]].v].co;
+ const float3 v3 = mesh.mvert[mesh.mloop[tri.tri[2]].v].co;
+
+ const float area = area_tri_v3(v1, v2, v3);
+ r_areas[i] = area;
+ }
+}
+
+static BLI_NOINLINE void compute_triangle_weights(Mesh &mesh,
+ Span<MLoopTri> triangles,
+ MutableSpan<float> r_weights)
+{
+ assert_same_size(triangles, r_weights);
+ compute_triangle_areas(mesh, triangles, r_weights);
+}
+
+static BLI_NOINLINE void compute_cumulative_distribution(Span<float> weights,
+ MutableSpan<float> r_cumulative_weights)
+{
+ BLI_assert(weights.size() + 1 == r_cumulative_weights.size());
+
+ r_cumulative_weights[0] = 0;
+ for (int i : weights.index_range()) {
+ r_cumulative_weights[i + 1] = r_cumulative_weights[i] + weights[i];
+ }
+}
+
+static void sample_cumulative_distribution_recursive(RandomNumberGenerator &rng,
+ int amount,
+ int start,
+ int one_after_end,
+ Span<float> cumulative_weights,
+ VectorAdaptor<int> &r_sampled_indices)
+{
+ BLI_assert(start <= one_after_end);
+ const int size = one_after_end - start;
+ if (size == 0) {
+ BLI_assert(amount == 0);
+ }
+ else if (amount == 0) {
+ return;
+ }
+ else if (size == 1) {
+ r_sampled_indices.append_n_times(start, amount);
+ }
+ else {
+ const int middle = start + size / 2;
+ const float left_weight = cumulative_weights[middle] - cumulative_weights[start];
+ const float right_weight = cumulative_weights[one_after_end] - cumulative_weights[middle];
+ BLI_assert(left_weight >= 0.0f && right_weight >= 0.0f);
+ const float weight_sum = left_weight + right_weight;
+ BLI_assert(weight_sum > 0.0f);
+
+ const float left_factor = left_weight / weight_sum;
+ const float right_factor = right_weight / weight_sum;
+
+ int left_amount = amount * left_factor;
+ int right_amount = amount * right_factor;
+
+ if (left_amount + right_amount < amount) {
+ BLI_assert(left_amount + right_amount + 1 == amount);
+ const float weight_per_item = weight_sum / amount;
+ const float total_remaining_weight = weight_sum -
+ (left_amount + right_amount) * weight_per_item;
+ const float left_remaining_weight = left_weight - left_amount * weight_per_item;
+ const float left_remaining_factor = left_remaining_weight / total_remaining_weight;
+ if (rng.get_float() < left_remaining_factor) {
+ left_amount++;
+ }
+ else {
+ right_amount++;
+ }
+ }
+
+ sample_cumulative_distribution_recursive(
+ rng, left_amount, start, middle, cumulative_weights, r_sampled_indices);
+ sample_cumulative_distribution_recursive(
+ rng, right_amount, middle, one_after_end, cumulative_weights, r_sampled_indices);
+ }
+}
+
+static BLI_NOINLINE void sample_cumulative_distribution(RandomNumberGenerator &rng,
+ Span<float> cumulative_weights,
+ MutableSpan<int> r_samples)
+{
+ VectorAdaptor<int> sampled_indices(r_samples);
+ sample_cumulative_distribution_recursive(rng,
+ r_samples.size(),
+ 0,
+ cumulative_weights.size() - 1,
+ cumulative_weights,
+ sampled_indices);
+ BLI_assert(sampled_indices.is_full());
+}
+
+static BLI_NOINLINE bool sample_weighted_buckets(RandomNumberGenerator &rng,
+ Span<float> weights,
+ MutableSpan<int> r_samples)
+{
+ Array<float> cumulative_weights(weights.size() + 1);
+ compute_cumulative_distribution(weights, cumulative_weights);
+
+ if (r_samples.size() > 0 && cumulative_weights.as_span().last() == 0.0f) {
+ /* All weights are zero. */
+ return false;
+ }
+
+ sample_cumulative_distribution(rng, cumulative_weights, r_samples);
+ return true;
+}
+
+static BLI_NOINLINE void sample_looptris(RandomNumberGenerator &rng,
+ Mesh &mesh,
+ Span<MLoopTri> triangles,
+ Span<int> triangles_to_sample,
+ MutableSpan<float3> r_sampled_positions,
+ MutableSpan<float3> r_sampled_normals)
+{
+ assert_same_size(triangles_to_sample, r_sampled_positions, r_sampled_normals);
+
+ MLoop *loops = mesh.mloop;
+ MVert *verts = mesh.mvert;
+
+ for (uint i : triangles_to_sample.index_range()) {
+ const uint triangle_index = triangles_to_sample[i];
+ const MLoopTri &triangle = triangles[triangle_index];
+
+ const float3 v1 = verts[loops[triangle.tri[0]].v].co;
+ const float3 v2 = verts[loops[triangle.tri[1]].v].co;
+ const float3 v3 = verts[loops[triangle.tri[2]].v].co;
+
+ const float3 bary_coords = rng.get_barycentric_coordinates();
+
+ float3 position;
+ interp_v3_v3v3v3(position, v1, v2, v3, bary_coords);
+
+ float3 normal;
+ normal_tri_v3(normal, v1, v2, v3);
+
+ r_sampled_positions[i] = position;
+ r_sampled_normals[i] = normal;
+ }
+}
+
+static BLI_NOINLINE bool compute_new_particle_attributes(EmitterSettings &settings,
+ TimeInterval emit_interval,
+ ParticleMeshEmitterSimulationState &state,
+ Vector<float3> &r_positions,
+ Vector<float3> &r_velocities,
+ Vector<float> &r_birth_times)
+{
+ if (settings.object == nullptr) {
+ return false;
+ }
+ if (settings.rate <= 0.000001f) {
+ return false;
+ }
+ if (settings.object->type != OB_MESH) {
+ return false;
+ }
+ Mesh &mesh = *(Mesh *)settings.object->data;
+ if (mesh.totvert == 0) {
+ return false;
+ }
+
+ const float4x4 local_to_world = settings.object->obmat;
+ float4x4 local_to_world_normal = local_to_world.inverted_affine().transposed();
+
+ const float start_time = emit_interval.start();
+ const uint32_t seed = DefaultHash<StringRef>{}(state.head.name);
+ RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed};
+
+ compute_birth_times(settings.rate, emit_interval, state, r_birth_times);
+ const int particle_amount = r_birth_times.size();
+ if (particle_amount == 0) {
+ return false;
+ }
+
+ rng.shuffle(r_birth_times.as_mutable_span());
+
+ Span<MLoopTri> triangles = get_mesh_triangles(mesh);
+ if (triangles.is_empty()) {
+ return false;
+ }
+
+ Array<float> triangle_weights(triangles.size());
+ compute_triangle_weights(mesh, triangles, triangle_weights);
+
+ Array<int> triangles_to_sample(particle_amount);
+ if (!sample_weighted_buckets(rng, triangle_weights, triangles_to_sample)) {
+ return false;
+ }
+
+ Array<float3> local_positions(particle_amount);
+ Array<float3> local_normals(particle_amount);
+ sample_looptris(rng, mesh, triangles, triangles_to_sample, local_positions, local_normals);
+
+ r_positions.reserve(particle_amount);
+ r_velocities.reserve(particle_amount);
+ for (int i : IndexRange(particle_amount)) {
+ float3 position = local_to_world * local_positions[i];
+ float3 normal = local_to_world_normal.ref_3x3() * local_normals[i];
+ normal.normalize();
+
+ r_positions.append(position);
+ r_velocities.append(normal);
+ }
+
+ state.last_birth_time = r_birth_times.last();
+ return true;
+}
+
+static BLI_NOINLINE EmitterSettings compute_settings(const fn::MultiFunction &inputs_fn,
+ ParticleEmitterContext &context)
+{
+ EmitterSettings parameters;
+
+ 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;
+ mf_params.add_uninitialized_single_output(&object_handle, "Object");
+ mf_params.add_uninitialized_single_output(&parameters.rate, "Rate");
+
+ inputs_fn.call(IndexRange(1), mf_params, mf_context);
+
+ parameters.object = context.solve_context().handle_map().lookup(object_handle);
+ return parameters;
+}
+
+void ParticleMeshEmitter::emit(ParticleEmitterContext &context) const
+{
+ auto *state = context.lookup_state<ParticleMeshEmitterSimulationState>(own_state_name_);
+ if (state == nullptr) {
+ return;
+ }
+
+ EmitterSettings settings = compute_settings(inputs_fn_, context);
+
+ Vector<float3> new_positions;
+ Vector<float3> new_velocities;
+ Vector<float> new_birth_times;
+
+ if (!compute_new_particle_attributes(settings,
+ context.emit_interval(),
+ *state,
+ new_positions,
+ new_velocities,
+ new_birth_times)) {
+ return;
+ }
+
+ for (StringRef name : particle_names_) {
+ ParticleAllocator *allocator = context.try_get_particle_allocator(name);
+ if (allocator == nullptr) {
+ continue;
+ }
+
+ int amount = new_positions.size();
+ fn::MutableAttributesRef attributes = allocator->allocate(amount);
+
+ attributes.get<float3>("Position").copy_from(new_positions);
+ attributes.get<float3>("Velocity").copy_from(new_velocities);
+ attributes.get<float>("Birth Time").copy_from(new_birth_times);
+ }
+}
+
+} // namespace blender::sim
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.hh b/source/blender/simulation/intern/particle_mesh_emitter.hh
new file mode 100644
index 00000000000..601697c9986
--- /dev/null
+++ b/source/blender/simulation/intern/particle_mesh_emitter.hh
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_PARTICLE_MESH_EMITTER_HH__
+#define __SIM_PARTICLE_MESH_EMITTER_HH__
+
+#include "simulation_solver_influences.hh"
+
+#include "FN_multi_function.hh"
+
+namespace blender::sim {
+
+class ParticleMeshEmitter final : public ParticleEmitter {
+ private:
+ std::string own_state_name_;
+ Array<std::string> particle_names_;
+ const fn::MultiFunction &inputs_fn_;
+
+ public:
+ ParticleMeshEmitter(std::string own_state_name,
+ Array<std::string> particle_names,
+ const fn::MultiFunction &inputs_fn)
+ : own_state_name_(std::move(own_state_name)),
+ particle_names_(particle_names),
+ inputs_fn_(inputs_fn)
+ {
+ }
+
+ ~ParticleMeshEmitter();
+
+ void emit(ParticleEmitterContext &context) const override;
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_PARTICLE_MESH_EMITTER_HH__ */
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
index 764e587d157..7554f61404a 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.cc
+++ b/source/blender/simulation/intern/simulation_collect_influences.cc
@@ -16,6 +16,7 @@
#include "simulation_collect_influences.hh"
#include "particle_function.hh"
+#include "particle_mesh_emitter.hh"
#include "FN_attributes_ref.hh"
#include "FN_multi_function_network_evaluation.hh"
@@ -23,6 +24,8 @@
#include "NOD_node_tree_multi_function.hh"
+#include "DEG_depsgraph_query.h"
+
#include "BLI_rand.hh"
namespace blender::sim {
@@ -119,13 +122,12 @@ static void find_and_deduplicate_particle_attribute_nodes(nodes::MFNetworkTreeMa
return;
}
- Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>>
+ MultiValueMap<std::pair<std::string, fn::MFDataType>, fn::MFNode *>
attribute_nodes_by_name_and_type;
for (int i : attribute_names->index_range()) {
- attribute_nodes_by_name_and_type
- .lookup_or_add_default(
- {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()})
- .append(&name_sockets[i]->node());
+ attribute_nodes_by_name_and_type.add(
+ {(*attribute_names)[i], name_sockets[i]->node().output(0).data_type()},
+ &name_sockets[i]->node());
}
Map<const fn::MFOutputSocket *, std::string> attribute_inputs;
@@ -234,11 +236,11 @@ class ParticleFunctionForce : public ParticleForce {
}
};
-static Vector<const ParticleForce *> create_forces_for_particle_simulation(
- const nodes::DNode &simulation_node,
- nodes::MFNetworkTreeMap &network_map,
- ResourceCollector &resources,
- DummyDataSources &data_sources)
+static void create_forces_for_particle_simulation(const nodes::DNode &simulation_node,
+ nodes::MFNetworkTreeMap &network_map,
+ ResourceCollector &resources,
+ DummyDataSources &data_sources,
+ SimulationInfluences &r_influences)
{
Vector<const ParticleForce *> forces;
for (const nodes::DOutputSocket *origin_socket :
@@ -261,7 +263,9 @@ static Vector<const ParticleForce *> create_forces_for_particle_simulation(
const ParticleForce &force = resources.construct<ParticleFunctionForce>(AT, *particle_fn);
forces.append(&force);
}
- return forces;
+
+ std::string particle_name = dnode_to_path(simulation_node);
+ r_influences.particle_forces.add_multiple(std::move(particle_name), forces);
}
static void collect_forces(nodes::MFNetworkTreeMap &network_map,
@@ -270,90 +274,11 @@ static void collect_forces(nodes::MFNetworkTreeMap &network_map,
SimulationInfluences &r_influences)
{
for (const nodes::DNode *dnode : get_particle_simulation_nodes(network_map.tree())) {
- std::string name = dnode_to_path(*dnode);
- Vector<const ParticleForce *> forces = create_forces_for_particle_simulation(
- *dnode, network_map, resources, data_sources);
- r_influences.particle_forces.add_new(std::move(name), std::move(forces));
+ create_forces_for_particle_simulation(
+ *dnode, network_map, resources, data_sources, r_influences);
}
}
-class MyBasicEmitter : public ParticleEmitter {
- private:
- Array<std::string> names_;
- std::string my_state_;
- const fn::MultiFunction &inputs_fn_;
- uint32_t seed_;
-
- public:
- MyBasicEmitter(Array<std::string> names,
- std::string my_state,
- const fn::MultiFunction &inputs_fn,
- uint32_t seed)
- : names_(std::move(names)),
- my_state_(std::move(my_state)),
- inputs_fn_(inputs_fn),
- seed_(seed)
- {
- }
-
- void emit(ParticleEmitterContext &context) const override
- {
- auto *state = context.solve_context().state_map().lookup<ParticleMeshEmitterSimulationState>(
- my_state_);
- if (state == nullptr) {
- return;
- }
-
- 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;
- }
-
- Vector<float3> new_positions;
- Vector<float3> new_velocities;
- Vector<float> new_birth_times;
-
- TimeInterval time_interval = context.simulation_time_interval();
- float start_time = time_interval.start();
- RandomNumberGenerator rng{(*(uint32_t *)&start_time) ^ seed_};
-
- const float time_between_particles = 1.0f / rate;
- while (state->last_birth_time + time_between_particles < time_interval.end()) {
- new_positions.append(rng.get_unit_float3() * 0.3 + float3(object->loc));
- new_velocities.append(rng.get_unit_float3());
- const float birth_time = state->last_birth_time + time_between_particles;
- new_birth_times.append(birth_time);
- state->last_birth_time = birth_time;
- }
-
- for (StringRef name : names_) {
- ParticleAllocator *allocator = context.try_get_particle_allocator(name);
- if (allocator == nullptr) {
- return;
- }
-
- int amount = new_positions.size();
- fn::MutableAttributesRef attributes = allocator->allocate(amount);
-
- 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)
{
@@ -394,11 +319,10 @@ static ParticleEmitter *create_particle_emitter(const nodes::DNode &dnode,
fn::MultiFunction &inputs_fn = resources.construct<fn::MFNetworkEvaluator>(
AT, Span<const fn::MFOutputSocket *>(), input_sockets.as_span());
- std::string my_state_name = dnode_to_path(dnode);
- r_required_states.add(my_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
- uint32_t seed = DefaultHash<std::string>{}(my_state_name);
- ParticleEmitter &emitter = resources.construct<MyBasicEmitter>(
- AT, std::move(names), std::move(my_state_name), inputs_fn, seed);
+ std::string own_state_name = dnode_to_path(dnode);
+ r_required_states.add(own_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
+ ParticleEmitter &emitter = resources.construct<ParticleMeshEmitter>(
+ AT, std::move(own_state_name), std::move(names), inputs_fn);
return &emitter;
}
@@ -434,23 +358,6 @@ 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,
@@ -478,8 +385,6 @@ void collect_simulation_influences(Simulation &simulation,
for (const nodes::DNode *dnode : get_particle_simulation_nodes(tree)) {
r_required_states.add(dnode_to_path(*dnode), SIM_TYPE_NAME_PARTICLE_SIMULATION);
}
-
- find_used_data_blocks(tree, r_influences);
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_collect_influences.hh b/source/blender/simulation/intern/simulation_collect_influences.hh
index 42cbea6977e..caf5a8c4ffa 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.hh
+++ b/source/blender/simulation/intern/simulation_collect_influences.hh
@@ -21,7 +21,7 @@
#include "BLI_resource_collector.hh"
-#include "simulation_solver.hh"
+#include "simulation_solver_influences.hh"
namespace blender::sim {
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc
index ee7a8d40035..5ab706dbb4b 100644
--- a/source/blender/simulation/intern/simulation_solver.cc
+++ b/source/blender/simulation/intern/simulation_solver.cc
@@ -17,12 +17,13 @@
#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"
+#include "DEG_depsgraph_query.h"
+
namespace blender::sim {
ParticleForce::~ParticleForce()
@@ -128,35 +129,32 @@ static void ensure_attributes_exist(ParticleSimulationState *state, const fn::At
}
}
-BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context,
- ParticleSimulationState &state,
- const fn::AttributesInfo &attributes_info)
+BLI_NOINLINE static void simulate_particle_chunk(SimulationSolveContext &solve_context,
+ ParticleSimulationState &state,
+ fn::MutableAttributesRef attributes,
+ MutableSpan<float> remaining_durations,
+ float end_time)
{
- CustomDataAttributesRef custom_data_attributes{
- state.attributes, state.tot_particles, attributes_info};
- fn::MutableAttributesRef attributes = custom_data_attributes;
-
- Array<float3> force_vectors{state.tot_particles, {0, 0, 0}};
- const Vector<const ParticleForce *> *forces =
- solve_context.influences().particle_forces.lookup_ptr(state.head.name);
+ int particle_amount = attributes.size();
+ Array<float3> force_vectors{particle_amount, {0, 0, 0}};
+ Span<const ParticleForce *> forces = solve_context.influences().particle_forces.lookup_as(
+ state.head.name);
- if (forces != nullptr) {
- ParticleChunkContext particle_chunk_context{IndexMask(state.tot_particles), attributes};
- ParticleForceContext particle_force_context{
- solve_context, particle_chunk_context, force_vectors};
+ ParticleChunkContext particle_chunk_context{IndexMask(particle_amount), attributes};
+ ParticleForceContext particle_force_context{
+ solve_context, particle_chunk_context, force_vectors};
- for (const ParticleForce *force : *forces) {
- force->add_force(particle_force_context);
- }
+ for (const ParticleForce *force : forces) {
+ force->add_force(particle_force_context);
}
MutableSpan<float3> positions = attributes.get<float3>("Position");
MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
MutableSpan<float> birth_times = attributes.get<float>("Birth Time");
MutableSpan<int> dead_states = attributes.get<int>("Dead");
- float end_time = solve_context.solve_interval().end();
- float time_step = solve_context.solve_interval().duration();
- for (int i : positions.index_range()) {
+
+ for (int i : IndexRange(particle_amount)) {
+ const float time_step = remaining_durations[i];
velocities[i] += force_vectors[i] * time_step;
positions[i] += velocities[i] * time_step;
@@ -166,6 +164,19 @@ BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &sol
}
}
+BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context,
+ ParticleSimulationState &state,
+ const fn::AttributesInfo &attributes_info)
+{
+ CustomDataAttributesRef custom_data_attributes{
+ state.attributes, state.tot_particles, attributes_info};
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+
+ Array<float> remaining_durations(state.tot_particles, solve_context.solve_interval().duration());
+ simulate_particle_chunk(
+ solve_context, state, attributes, remaining_durations, solve_context.solve_interval().end());
+}
+
BLI_NOINLINE static void run_emitters(SimulationSolveContext &solve_context,
ParticleAllocators &particle_allocators)
{
@@ -233,7 +244,7 @@ BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationSta
if (layer.data != nullptr) {
MEM_freeN(layer.data);
}
- layer.data = new_buffer.buffer();
+ layer.data = new_buffer.data();
}
BLI_assert(dead_layer != nullptr);
@@ -246,56 +257,10 @@ 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))
+ const SimulationInfluences &UNUSED(influences),
+ const bke::PersistentDataHandleMap &UNUSED(handle_map))
{
simulation.current_simulation_time = 0.0f;
}
@@ -303,15 +268,9 @@ void initialize_simulation_states(Simulation &simulation,
void solve_simulation_time_step(Simulation &simulation,
Depsgraph &depsgraph,
const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map,
float 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);
- }
-
SimulationStateMap state_map;
LISTBASE_FOREACH (SimulationState *, state, &simulation.states) {
state_map.add(state);
@@ -323,7 +282,6 @@ void solve_simulation_time_step(Simulation &simulation,
TimeInterval(simulation.current_simulation_time, time_step),
state_map,
handle_map};
- TimeInterval simulation_time_interval{simulation.current_simulation_time, time_step};
Span<ParticleSimulationState *> particle_simulation_states =
state_map.lookup<ParticleSimulationState>();
@@ -353,10 +311,21 @@ void solve_simulation_time_step(Simulation &simulation,
for (ParticleSimulationState *state : particle_simulation_states) {
ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name);
+
+ for (fn::MutableAttributesRef attributes : allocator.get_allocations()) {
+ Array<float> remaining_durations(attributes.size());
+ Span<float> birth_times = attributes.get<float>("Birth Time");
+ const float end_time = solve_context.solve_interval().end();
+ for (int i : attributes.index_range()) {
+ remaining_durations[i] = end_time - birth_times[i];
+ }
+ simulate_particle_chunk(solve_context, *state, attributes, remaining_durations, end_time);
+ }
+
remove_dead_and_add_new_particles(*state, allocator);
}
- simulation.current_simulation_time = simulation_time_interval.end();
+ simulation.current_simulation_time = solve_context.solve_interval().end();
}
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver.hh b/source/blender/simulation/intern/simulation_solver.hh
index 2dc0921ad9e..ccf4855a9a1 100644
--- a/source/blender/simulation/intern/simulation_solver.hh
+++ b/source/blender/simulation/intern/simulation_solver.hh
@@ -17,259 +17,21 @@
#ifndef __SIM_SIMULATION_SOLVER_HH__
#define __SIM_SIMULATION_SOLVER_HH__
-#include "BLI_float3.hh"
-#include "BLI_span.hh"
-
-#include "DNA_simulation_types.h"
-
-#include "FN_attributes_ref.hh"
-
-#include "BKE_persistent_data_handle.hh"
-#include "BKE_simulation.h"
-
-#include "particle_allocator.hh"
-#include "time_interval.hh"
+#include "simulation_collect_influences.hh"
struct Depsgraph;
namespace blender::sim {
-class ParticleEmitterContext;
-class ParticleForceContext;
-
-class ParticleEmitter {
- public:
- virtual ~ParticleEmitter();
- virtual void emit(ParticleEmitterContext &context) const = 0;
-};
-
-class ParticleForce {
- public:
- virtual ~ParticleForce();
- virtual void add_force(ParticleForceContext &context) const = 0;
-};
-
-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 SimulationStateMap {
- private:
- Map<StringRefNull, SimulationState *> states_by_name_;
- Map<StringRefNull, Vector<SimulationState *>> states_by_type_;
-
- public:
- void add(SimulationState *state)
- {
- states_by_name_.add_new(state->name, state);
- states_by_type_.lookup_or_add_default(state->type).append(state);
- }
-
- template<typename StateType> StateType *lookup(StringRef name) const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return (StateType *)this->lookup_name_type(name, type);
- }
-
- template<typename StateType> Span<StateType *> lookup() const
- {
- const char *type = BKE_simulation_get_state_type_name<StateType>();
- return this->lookup_type(type).cast<StateType *>();
- }
-
- SimulationState *lookup_name_type(StringRef name, StringRef type) const
- {
- SimulationState *state = states_by_name_.lookup_default_as(name, nullptr);
- if (state == nullptr) {
- return nullptr;
- }
- if (state->type == type) {
- return state;
- }
- return nullptr;
- }
-
- Span<SimulationState *> lookup_type(StringRef type) const
- {
- const Vector<SimulationState *> *states = states_by_type_.lookup_ptr_as(type);
- if (states == nullptr) {
- return {};
- }
- else {
- return states->as_span();
- }
- }
-};
-
-class SimulationSolveContext {
- private:
- Simulation &simulation_;
- Depsgraph &depsgraph_;
- const SimulationInfluences &influences_;
- TimeInterval solve_interval_;
- const SimulationStateMap &state_map_;
- const bke::PersistentDataHandleMap &id_handle_map_;
-
- public:
- SimulationSolveContext(Simulation &simulation,
- Depsgraph &depsgraph,
- const SimulationInfluences &influences,
- TimeInterval solve_interval,
- const SimulationStateMap &state_map,
- const bke::PersistentDataHandleMap &handle_map)
- : simulation_(simulation),
- depsgraph_(depsgraph),
- influences_(influences),
- solve_interval_(solve_interval),
- state_map_(state_map),
- id_handle_map_(handle_map)
- {
- }
-
- TimeInterval solve_interval() const
- {
- return solve_interval_;
- }
-
- const SimulationInfluences &influences() const
- {
- return influences_;
- }
-
- const bke::PersistentDataHandleMap &handle_map() const
- {
- return id_handle_map_;
- }
-
- const SimulationStateMap &state_map() const
- {
- return state_map_;
- }
-};
-
-class ParticleAllocators {
- private:
- Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators_;
-
- public:
- ParticleAllocators(Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators)
- : allocators_(allocators)
- {
- }
-
- ParticleAllocator *try_get_allocator(StringRef particle_simulation_name)
- {
- auto *ptr = allocators_.lookup_ptr_as(particle_simulation_name);
- if (ptr != nullptr) {
- return ptr->get();
- }
- else {
- return nullptr;
- }
- }
-};
-
-class ParticleChunkContext {
- private:
- IndexMask index_mask_;
- fn::MutableAttributesRef attributes_;
-
- public:
- ParticleChunkContext(IndexMask index_mask, fn::MutableAttributesRef attributes)
- : index_mask_(index_mask), attributes_(attributes)
- {
- }
-
- IndexMask index_mask() const
- {
- return index_mask_;
- }
-
- fn::MutableAttributesRef attributes()
- {
- return attributes_;
- }
-
- fn::AttributesRef attributes() const
- {
- return attributes_;
- }
-};
-
-class ParticleEmitterContext {
- private:
- SimulationSolveContext &solve_context_;
- ParticleAllocators &particle_allocators_;
- TimeInterval simulation_time_interval_;
-
- public:
- ParticleEmitterContext(SimulationSolveContext &solve_context,
- ParticleAllocators &particle_allocators,
- TimeInterval simulation_time_interval)
- : solve_context_(solve_context),
- particle_allocators_(particle_allocators),
- simulation_time_interval_(simulation_time_interval)
- {
- }
-
- SimulationSolveContext &solve_context()
- {
- return solve_context_;
- }
-
- ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
- {
- return particle_allocators_.try_get_allocator(particle_simulation_name);
- }
-
- TimeInterval simulation_time_interval() const
- {
- return simulation_time_interval_;
- }
-};
-
-class ParticleForceContext {
- private:
- SimulationSolveContext &solve_context_;
- const ParticleChunkContext &particle_chunk_context_;
- MutableSpan<float3> force_dst_;
-
- public:
- ParticleForceContext(SimulationSolveContext &solve_context,
- const ParticleChunkContext &particle_chunk_context,
- MutableSpan<float3> force_dst)
- : solve_context_(solve_context),
- particle_chunk_context_(particle_chunk_context),
- force_dst_(force_dst)
- {
- }
-
- SimulationSolveContext &solve_context()
- {
- return solve_context_;
- }
-
- const ParticleChunkContext &particle_chunk() const
- {
- return particle_chunk_context_;
- }
-
- MutableSpan<float3> force_dst()
- {
- return force_dst_;
- }
-};
-
void initialize_simulation_states(Simulation &simulation,
Depsgraph &depsgraph,
- const SimulationInfluences &influences);
+ const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map);
void solve_simulation_time_step(Simulation &simulation,
Depsgraph &depsgraph,
const SimulationInfluences &influences,
+ const bke::PersistentDataHandleMap &handle_map,
float time_step);
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/simulation_solver_influences.hh b/source/blender/simulation/intern/simulation_solver_influences.hh
new file mode 100644
index 00000000000..95e6463e60d
--- /dev/null
+++ b/source/blender/simulation/intern/simulation_solver_influences.hh
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+#ifndef __SIM_SIMULATION_SOLVER_INFLUENCES_HH__
+#define __SIM_SIMULATION_SOLVER_INFLUENCES_HH__
+
+#include "BLI_float3.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_span.hh"
+
+#include "DNA_simulation_types.h"
+
+#include "FN_attributes_ref.hh"
+
+#include "BKE_persistent_data_handle.hh"
+#include "BKE_simulation.h"
+
+#include "particle_allocator.hh"
+#include "time_interval.hh"
+
+namespace blender::sim {
+
+class ParticleEmitterContext;
+class ParticleForceContext;
+
+class ParticleEmitter {
+ public:
+ virtual ~ParticleEmitter();
+ virtual void emit(ParticleEmitterContext &context) const = 0;
+};
+
+class ParticleForce {
+ public:
+ virtual ~ParticleForce();
+ virtual void add_force(ParticleForceContext &context) const = 0;
+};
+
+struct SimulationInfluences {
+ MultiValueMap<std::string, const ParticleForce *> particle_forces;
+ Map<std::string, fn::AttributesInfoBuilder *> particle_attributes_builder;
+ Vector<const ParticleEmitter *> particle_emitters;
+};
+
+class SimulationStateMap {
+ private:
+ Map<StringRefNull, SimulationState *> states_by_name_;
+ MultiValueMap<StringRefNull, SimulationState *> states_by_type_;
+
+ public:
+ void add(SimulationState *state)
+ {
+ states_by_name_.add_new(state->name, state);
+ states_by_type_.add(state->type, state);
+ }
+
+ template<typename StateType> StateType *lookup(StringRef name) const
+ {
+ const char *type = BKE_simulation_get_state_type_name<StateType>();
+ return (StateType *)this->lookup_name_type(name, type);
+ }
+
+ template<typename StateType> Span<StateType *> lookup() const
+ {
+ const char *type = BKE_simulation_get_state_type_name<StateType>();
+ return this->lookup_type(type).cast<StateType *>();
+ }
+
+ SimulationState *lookup_name_type(StringRef name, StringRef type) const
+ {
+ SimulationState *state = states_by_name_.lookup_default_as(name, nullptr);
+ if (state == nullptr) {
+ return nullptr;
+ }
+ if (state->type == type) {
+ return state;
+ }
+ return nullptr;
+ }
+
+ Span<SimulationState *> lookup_type(StringRef type) const
+ {
+ return states_by_type_.lookup_as(type);
+ }
+};
+
+class SimulationSolveContext {
+ private:
+ Simulation &simulation_;
+ Depsgraph &depsgraph_;
+ const SimulationInfluences &influences_;
+ TimeInterval solve_interval_;
+ const SimulationStateMap &state_map_;
+ const bke::PersistentDataHandleMap &id_handle_map_;
+
+ public:
+ SimulationSolveContext(Simulation &simulation,
+ Depsgraph &depsgraph,
+ const SimulationInfluences &influences,
+ TimeInterval solve_interval,
+ const SimulationStateMap &state_map,
+ const bke::PersistentDataHandleMap &handle_map)
+ : simulation_(simulation),
+ depsgraph_(depsgraph),
+ influences_(influences),
+ solve_interval_(solve_interval),
+ state_map_(state_map),
+ id_handle_map_(handle_map)
+ {
+ }
+
+ TimeInterval solve_interval() const
+ {
+ return solve_interval_;
+ }
+
+ const SimulationInfluences &influences() const
+ {
+ return influences_;
+ }
+
+ const bke::PersistentDataHandleMap &handle_map() const
+ {
+ return id_handle_map_;
+ }
+
+ const SimulationStateMap &state_map() const
+ {
+ return state_map_;
+ }
+};
+
+class ParticleAllocators {
+ private:
+ Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators_;
+
+ public:
+ ParticleAllocators(Map<std::string, std::unique_ptr<ParticleAllocator>> &allocators)
+ : allocators_(allocators)
+ {
+ }
+
+ ParticleAllocator *try_get_allocator(StringRef particle_simulation_name)
+ {
+ auto *ptr = allocators_.lookup_ptr_as(particle_simulation_name);
+ if (ptr != nullptr) {
+ return ptr->get();
+ }
+ else {
+ return nullptr;
+ }
+ }
+};
+
+class ParticleChunkContext {
+ private:
+ IndexMask index_mask_;
+ fn::MutableAttributesRef attributes_;
+
+ public:
+ ParticleChunkContext(IndexMask index_mask, fn::MutableAttributesRef attributes)
+ : index_mask_(index_mask), attributes_(attributes)
+ {
+ }
+
+ IndexMask index_mask() const
+ {
+ return index_mask_;
+ }
+
+ fn::MutableAttributesRef attributes()
+ {
+ return attributes_;
+ }
+
+ fn::AttributesRef attributes() const
+ {
+ return attributes_;
+ }
+};
+
+class ParticleEmitterContext {
+ private:
+ SimulationSolveContext &solve_context_;
+ ParticleAllocators &particle_allocators_;
+ TimeInterval emit_interval_;
+
+ public:
+ ParticleEmitterContext(SimulationSolveContext &solve_context,
+ ParticleAllocators &particle_allocators,
+ TimeInterval emit_interval)
+ : solve_context_(solve_context),
+ particle_allocators_(particle_allocators),
+ emit_interval_(emit_interval)
+ {
+ }
+
+ template<typename StateType> StateType *lookup_state(StringRef name)
+ {
+ return solve_context_.state_map().lookup<StateType>(name);
+ }
+
+ SimulationSolveContext &solve_context()
+ {
+ return solve_context_;
+ }
+
+ ParticleAllocator *try_get_particle_allocator(StringRef particle_simulation_name)
+ {
+ return particle_allocators_.try_get_allocator(particle_simulation_name);
+ }
+
+ TimeInterval emit_interval() const
+ {
+ return emit_interval_;
+ }
+};
+
+class ParticleForceContext {
+ private:
+ SimulationSolveContext &solve_context_;
+ const ParticleChunkContext &particle_chunk_context_;
+ MutableSpan<float3> force_dst_;
+
+ public:
+ ParticleForceContext(SimulationSolveContext &solve_context,
+ const ParticleChunkContext &particle_chunk_context,
+ MutableSpan<float3> force_dst)
+ : solve_context_(solve_context),
+ particle_chunk_context_(particle_chunk_context),
+ force_dst_(force_dst)
+ {
+ }
+
+ SimulationSolveContext &solve_context()
+ {
+ return solve_context_;
+ }
+
+ const ParticleChunkContext &particle_chunk() const
+ {
+ return particle_chunk_context_;
+ }
+
+ MutableSpan<float3> force_dst()
+ {
+ return force_dst_;
+ }
+};
+
+} // namespace blender::sim
+
+#endif /* __SIM_SIMULATION_SOLVER_INFLUENCES_HH__ */
diff --git a/source/blender/simulation/intern/simulation_update.cc b/source/blender/simulation/intern/simulation_update.cc
index 09219e0238f..3303145b891 100644
--- a/source/blender/simulation/intern/simulation_update.cc
+++ b/source/blender/simulation/intern/simulation_update.cc
@@ -17,6 +17,7 @@
#include "SIM_simulation_update.hh"
#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
#include "BKE_simulation.h"
#include "DNA_scene_types.h"
@@ -29,8 +30,11 @@
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_rand.h"
+#include "BLI_set.hh"
#include "BLI_vector.hh"
+#include "NOD_node_tree_dependencies.hh"
+
#include "particle_function.hh"
#include "simulation_collect_influences.hh"
#include "simulation_solver.hh"
@@ -108,13 +112,19 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
SimulationInfluences influences;
RequiredStates required_states;
- /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
- collect_simulation_influences(*simulation_orig, resources, influences, required_states);
+ collect_simulation_influences(*simulation_cow, resources, influences, required_states);
+
+ bke::PersistentDataHandleMap handle_map;
+ LISTBASE_FOREACH (
+ PersistentDataHandleItem *, handle_item, &simulation_orig->persistent_data_handles) {
+ ID *id_cow = DEG_get_evaluated_id(depsgraph, handle_item->id);
+ handle_map.add(handle_item->handle, *id_cow);
+ }
if (current_frame == 1) {
reinitialize_empty_simulation_states(simulation_orig, required_states);
- initialize_simulation_states(*simulation_orig, *depsgraph, influences);
+ initialize_simulation_states(*simulation_orig, *depsgraph, influences, handle_map);
simulation_orig->current_frame = 1;
copy_states_to_cow(simulation_orig, simulation_cow);
@@ -123,11 +133,88 @@ void update_simulation_in_depsgraph(Depsgraph *depsgraph,
update_simulation_state_list(simulation_orig, required_states);
float time_step = 1.0f / 24.0f;
- solve_simulation_time_step(*simulation_orig, *depsgraph, influences, time_step);
+ solve_simulation_time_step(*simulation_orig, *depsgraph, influences, handle_map, time_step);
simulation_orig->current_frame = current_frame;
copy_states_to_cow(simulation_orig, simulation_cow);
}
}
+/* Returns true when dependencies have changed. */
+bool update_simulation_dependencies(Simulation *simulation)
+{
+ nodes::NodeTreeDependencies dependencies = nodes::find_node_tree_dependencies(
+ *simulation->nodetree);
+
+ ListBase *handle_list = &simulation->persistent_data_handles;
+
+ bool dependencies_changed = false;
+
+ Map<ID *, PersistentDataHandleItem *> handle_item_by_id;
+ Map<PersistentDataHandleItem *, int> old_flag_by_handle_item;
+ Set<int> used_handles;
+
+ /* Remove unused handle items and clear flags that are reinitialized later. */
+ LISTBASE_FOREACH_MUTABLE (PersistentDataHandleItem *, handle_item, handle_list) {
+ if (dependencies.depends_on(handle_item->id)) {
+ handle_item_by_id.add_new(handle_item->id, handle_item);
+ used_handles.add_new(handle_item->handle);
+ old_flag_by_handle_item.add_new(handle_item, handle_item->flag);
+ handle_item->flag &= ~(SIM_HANDLE_DEPENDS_ON_TRANSFORM | SIM_HANDLE_DEPENDS_ON_GEOMETRY);
+ }
+ else {
+ if (handle_item->id != nullptr) {
+ id_us_min(handle_item->id);
+ }
+ BLI_remlink(handle_list, handle_item);
+ MEM_freeN(handle_item);
+ dependencies_changed = true;
+ }
+ }
+
+ /* Add handle items for new id dependencies. */
+ int next_handle = 0;
+ for (ID *id : dependencies.id_dependencies()) {
+ handle_item_by_id.lookup_or_add_cb(id, [&]() {
+ while (used_handles.contains(next_handle)) {
+ next_handle++;
+ }
+ used_handles.add_new(next_handle);
+
+ PersistentDataHandleItem *handle_item = (PersistentDataHandleItem *)MEM_callocN(
+ sizeof(*handle_item), AT);
+ id_us_plus(id);
+ handle_item->id = id;
+ handle_item->handle = next_handle;
+ BLI_addtail(handle_list, handle_item);
+
+ return handle_item;
+ });
+ }
+
+ /* Set appropriate dependency flags. */
+ for (Object *object : dependencies.transform_dependencies()) {
+ PersistentDataHandleItem *handle_item = handle_item_by_id.lookup(&object->id);
+ handle_item->flag |= SIM_HANDLE_DEPENDS_ON_TRANSFORM;
+ }
+ for (Object *object : dependencies.geometry_dependencies()) {
+ PersistentDataHandleItem *handle_item = handle_item_by_id.lookup(&object->id);
+ handle_item->flag |= SIM_HANDLE_DEPENDS_ON_GEOMETRY;
+ }
+
+ if (!dependencies_changed) {
+ /* Check if any flags have changed. */
+ LISTBASE_FOREACH (PersistentDataHandleItem *, handle_item, handle_list) {
+ int old_flag = old_flag_by_handle_item.lookup_default(handle_item, 0);
+ int new_flag = handle_item->flag;
+ if (old_flag != new_flag) {
+ dependencies_changed = true;
+ break;
+ }
+ }
+ }
+
+ return dependencies_changed;
+}
+
} // namespace blender::sim
diff --git a/source/blender/simulation/intern/time_interval.hh b/source/blender/simulation/intern/time_interval.hh
index 49600dd10de..75ef4b21c33 100644
--- a/source/blender/simulation/intern/time_interval.hh
+++ b/source/blender/simulation/intern/time_interval.hh
@@ -22,7 +22,7 @@
namespace blender::sim {
/**
- * The start time is inclusive and the end time is exclusive. The duration is zero, the interval
+ * The start time is exclusive and the end time is inclusive. If the duration is zero, the interval
* describes a single point in time.
*/
class TimeInterval {