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/intern/simulation_collect_influences.cc')
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc173
1 files changed, 148 insertions, 25 deletions
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
index 4d339f9e323..818415e5d88 100644
--- a/source/blender/simulation/intern/simulation_collect_influences.cc
+++ b/source/blender/simulation/intern/simulation_collect_influences.cc
@@ -367,6 +367,17 @@ static const ParticleFunction *create_particle_function_for_inputs(
return &particle_fn;
}
+static const ParticleFunction *create_particle_function_for_inputs(
+ CollectContext &context, Span<const DInputSocket *> dsockets_to_compute)
+{
+ Vector<const MFInputSocket *> sockets_to_compute;
+ for (const DInputSocket *dsocket : dsockets_to_compute) {
+ const MFInputSocket &socket = context.network_map.lookup_dummy(*dsocket);
+ sockets_to_compute.append(&socket);
+ }
+ return create_particle_function_for_inputs(context, sockets_to_compute);
+}
+
class ParticleFunctionForce : public ParticleForce {
private:
const ParticleFunction &particle_fn_;
@@ -401,11 +412,8 @@ static void create_forces_for_particle_simulation(CollectContext &context,
continue;
}
- const MFInputSocket &force_socket = context.network_map.lookup_dummy(
- origin_node.input(0, "Force"));
-
- const ParticleFunction *particle_fn = create_particle_function_for_inputs(context,
- {&force_socket});
+ const ParticleFunction *particle_fn = create_particle_function_for_inputs(
+ context, {&origin_node.input(0, "Force")});
if (particle_fn == nullptr) {
continue;
@@ -434,7 +442,7 @@ static ParticleEmitter *create_particle_emitter(CollectContext &context, const D
return nullptr;
}
- Array<const MFInputSocket *> input_sockets{dnode.inputs().size()};
+ Array<const MFInputSocket *> input_sockets{2};
for (int i : input_sockets.index_range()) {
input_sockets[i] = &context.network_map.lookup_dummy(dnode.input(i));
}
@@ -446,10 +454,13 @@ static ParticleEmitter *create_particle_emitter(CollectContext &context, const D
MultiFunction &inputs_fn = context.resources.construct<MFNetworkEvaluator>(
AT, Span<const MFOutputSocket *>(), input_sockets.as_span());
+ const ParticleAction *birth_action = create_particle_action(
+ context, dnode.input(2, "Execute"), names);
+
StringRefNull own_state_name = get_identifier(context, dnode);
context.required_states.add(own_state_name, SIM_TYPE_NAME_PARTICLE_MESH_EMITTER);
ParticleEmitter &emitter = context.resources.construct<ParticleMeshEmitter>(
- AT, own_state_name, names.as_span(), inputs_fn);
+ AT, own_state_name, names.as_span(), inputs_fn, birth_action);
return &emitter;
}
@@ -490,15 +501,10 @@ static void collect_time_step_events(CollectContext &context)
{
for (const DNode *event_dnode : nodes_by_type(context, "SimulationNodeParticleTimeStepEvent")) {
const DInputSocket &execute_input = event_dnode->input(0);
- if (execute_input.linked_sockets().size() != 1) {
- continue;
- }
-
Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
event_dnode->output(0));
- const DOutputSocket &execute_source = *execute_input.linked_sockets()[0];
- const ParticleAction *action = create_particle_action(context, execute_source, particle_names);
+ const ParticleAction *action = create_particle_action(context, execute_input, particle_names);
if (action == nullptr) {
continue;
}
@@ -570,6 +576,10 @@ class SetParticleAttributeAction : public ParticleAction {
cpp_type_.copy_to_initialized_indices(
value_array.data(), attribute_array->data(), context.particles.index_mask);
}
+
+ if (attribute_name_ == "Velocity") {
+ context.particles.update_diffs_after_velocity_change();
+ }
}
};
@@ -595,21 +605,28 @@ static const ParticleAction *create_set_particle_attribute_action(
CollectContext &context, const DOutputSocket &dsocket, Span<StringRefNull> particle_names)
{
const DNode &dnode = dsocket.node();
+
+ const ParticleAction *previous_action = create_particle_action(
+ context, dnode.input(0), particle_names);
+
MFInputSocket &name_socket = context.network_map.lookup_dummy(dnode.input(1));
MFInputSocket &value_socket = name_socket.node().input(1);
std::optional<Array<std::string>> names = compute_global_string_inputs(context.network_map,
{&name_socket});
if (!names.has_value()) {
- return nullptr;
+ return previous_action;
}
std::string attribute_name = (*names)[0];
+ if (attribute_name.empty()) {
+ return previous_action;
+ }
const CPPType &attribute_type = value_socket.data_type().single_type();
const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context,
{&value_socket});
if (inputs_fn == nullptr) {
- return nullptr;
+ return previous_action;
}
for (StringRef particle_name : particle_names) {
@@ -620,9 +637,6 @@ static const ParticleAction *create_set_particle_attribute_action(
ParticleAction &this_action = context.resources.construct<SetParticleAttributeAction>(
AT, attribute_name, attribute_type, *inputs_fn);
- const ParticleAction *previous_action = create_particle_action(
- context, dnode.input(0), particle_names);
-
return concatenate_actions(context, {previous_action, &this_action});
}
@@ -674,12 +688,18 @@ class ParticleConditionAction : public ParticleAction {
}
if (action_true_ != nullptr) {
- ParticleChunkContext chunk_context{true_indices.as_span(), context.particles.attributes};
+ ParticleChunkContext chunk_context{context.particles.state,
+ true_indices.as_span(),
+ context.particles.attributes,
+ context.particles.integration};
ParticleActionContext action_context{context.solve_context, chunk_context};
action_true_->execute(action_context);
}
if (action_false_ != nullptr) {
- ParticleChunkContext chunk_context{false_indices.as_span(), context.particles.attributes};
+ ParticleChunkContext chunk_context{context.particles.state,
+ false_indices.as_span(),
+ context.particles.attributes,
+ context.particles.integration};
ParticleActionContext action_context{context.solve_context, chunk_context};
action_false_->execute(action_context);
}
@@ -692,10 +712,9 @@ static const ParticleAction *create_particle_condition_action(CollectContext &co
Span<StringRefNull> particle_names)
{
const DNode &dnode = dsocket.node();
- MFInputSocket &condition_socket = context.network_map.lookup_dummy(dnode.input(0));
- const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context,
- {&condition_socket});
+ const ParticleFunction *inputs_fn = create_particle_function_for_inputs(
+ context, {&dnode.input(0, "Condition")});
if (inputs_fn == nullptr) {
return nullptr;
}
@@ -712,17 +731,32 @@ static const ParticleAction *create_particle_condition_action(CollectContext &co
AT, *inputs_fn, true_action, false_action);
}
+class KillParticleAction : public ParticleAction {
+ public:
+ void execute(ParticleActionContext &context) const override
+ {
+ MutableSpan<int> dead_states = context.particles.attributes.get<int>("Dead");
+ for (int i : context.particles.index_mask) {
+ dead_states[i] = true;
+ }
+ }
+};
+
static const ParticleAction *create_particle_action(CollectContext &context,
const DOutputSocket &dsocket,
Span<StringRefNull> particle_names)
{
const DNode &dnode = dsocket.node();
- if (dnode.idname() == "SimulationNodeSetParticleAttribute") {
+ StringRef idname = dnode.idname();
+ if (idname == "SimulationNodeSetParticleAttribute") {
return create_set_particle_attribute_action(context, dsocket, particle_names);
}
- if (dnode.idname() == "SimulationNodeExecuteCondition") {
+ if (idname == "SimulationNodeExecuteCondition") {
return create_particle_condition_action(context, dsocket, particle_names);
}
+ if (idname == "SimulationNodeKillParticle") {
+ return &context.resources.construct<KillParticleAction>(AT);
+ }
return nullptr;
}
@@ -740,6 +774,7 @@ static void initialize_particle_attribute_builders(CollectContext &context)
/* TODO: Use uint32_t, but we don't have a corresponding custom property type. */
attributes_builder.add<int>("Hash", 0);
attributes_builder.add<float>("Birth Time", 0.0f);
+ attributes_builder.add<float>("Radius", 0.02f);
context.influences.particle_attributes_builder.add_new(name, &attributes_builder);
}
}
@@ -752,6 +787,93 @@ static void optimize_function_network(CollectContext &context)
// WM_clipboard_text_set(network.to_dot().c_str(), false);
}
+class AgeReachedEvent : public ParticleEvent {
+ private:
+ std::string attribute_name_;
+ const ParticleFunction &inputs_fn_;
+ const ParticleAction &action_;
+
+ public:
+ AgeReachedEvent(std::string attribute_name,
+ const ParticleFunction &inputs_fn,
+ const ParticleAction &action)
+ : attribute_name_(std::move(attribute_name)), inputs_fn_(inputs_fn), action_(action)
+ {
+ }
+
+ void filter(ParticleEventFilterContext &context) const override
+ {
+ Span<float> birth_times = context.particles.attributes.get<float>("Birth Time");
+ std::optional<Span<int>> has_been_triggered = context.particles.attributes.try_get<int>(
+ attribute_name_);
+ if (!has_been_triggered.has_value()) {
+ return;
+ }
+
+ ParticleFunctionEvaluator evaluator{inputs_fn_, context.solve_context, context.particles};
+ evaluator.compute();
+ VSpan<float> trigger_ages = evaluator.get<float>(0, "Age");
+
+ const float end_time = context.particles.integration->end_time;
+ for (int i : context.particles.index_mask) {
+ if ((*has_been_triggered)[i]) {
+ continue;
+ }
+ const float trigger_age = trigger_ages[i];
+ const float birth_time = birth_times[i];
+ const float trigger_time = birth_time + trigger_age;
+ if (trigger_time > end_time) {
+ continue;
+ }
+
+ const float duration = context.particles.integration->durations[i];
+ TimeInterval interval(end_time - duration, duration);
+ const float time_factor = interval.safe_factor_at_time(trigger_time);
+
+ context.factor_dst[i] = std::max<float>(0.0f, time_factor);
+ }
+ }
+
+ void execute(ParticleActionContext &context) const override
+ {
+ MutableSpan<int> has_been_triggered = context.particles.attributes.get<int>(attribute_name_);
+ for (int i : context.particles.index_mask) {
+ has_been_triggered[i] = 1;
+ }
+ action_.execute(context);
+ }
+};
+
+static void collect_age_reached_events(CollectContext &context)
+{
+ for (const DNode *dnode : nodes_by_type(context, "SimulationNodeAgeReachedEvent")) {
+ const DInputSocket &age_input = dnode->input(0, "Age");
+ const DInputSocket &execute_input = dnode->input(1, "Execute");
+ Array<StringRefNull> particle_names = find_linked_particle_simulations(context,
+ dnode->output(0));
+ const ParticleAction *action = create_particle_action(context, execute_input, particle_names);
+ if (action == nullptr) {
+ continue;
+ }
+ const ParticleFunction *inputs_fn = create_particle_function_for_inputs(context, {&age_input});
+ if (inputs_fn == nullptr) {
+ continue;
+ }
+
+ std::string attribute_name = get_identifier(context, *dnode);
+ const ParticleEvent &event = context.resources.construct<AgeReachedEvent>(
+ AT, attribute_name, *inputs_fn, *action);
+ for (StringRefNull particle_name : particle_names) {
+ const bool added_attribute = context.influences.particle_attributes_builder
+ .lookup_as(particle_name)
+ ->add<int>(attribute_name, 0);
+ if (added_attribute) {
+ context.influences.particle_events.add_as(particle_name, &event);
+ }
+ }
+ }
+}
+
void collect_simulation_influences(Simulation &simulation,
ResourceCollector &resources,
SimulationInfluences &r_influences,
@@ -773,6 +895,7 @@ void collect_simulation_influences(Simulation &simulation,
collect_emitters(context);
collect_birth_events(context);
collect_time_step_events(context);
+ collect_age_reached_events(context);
optimize_function_network(context);