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')
-rw-r--r--source/blender/blenkernel/BKE_node.h3
-rw-r--r--source/blender/blenkernel/intern/node.c3
-rw-r--r--source/blender/functions/intern/attributes_ref.cc4
-rw-r--r--source/blender/nodes/CMakeLists.txt3
-rw-r--r--source/blender/nodes/NOD_function.h1
-rw-r--r--source/blender/nodes/NOD_simulation.h2
-rw-r--r--source/blender/nodes/NOD_static_types.h4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc89
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_age_reached_event.cc38
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_kill_particle.cc36
-rw-r--r--source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc1
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.cc10
-rw-r--r--source/blender/simulation/intern/particle_mesh_emitter.hh7
-rw-r--r--source/blender/simulation/intern/simulation_collect_influences.cc132
-rw-r--r--source/blender/simulation/intern/simulation_solver.cc3
15 files changed, 295 insertions, 41 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 4c55488ecd5..f1502a9b87d 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1331,6 +1331,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define SIM_NODE_EMIT_PARTICLES 1009
#define SIM_NODE_TIME 1010
#define SIM_NODE_PARTICLE_ATTRIBUTE 1011
+#define SIM_NODE_AGE_REACHED_EVENT 1012
+#define SIM_NODE_KILL_PARTICLE 1013
/** \} */
@@ -1344,6 +1346,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define FN_NODE_GROUP_INSTANCE_ID 1203
#define FN_NODE_COMBINE_STRINGS 1204
#define FN_NODE_OBJECT_TRANSFORMS 1205
+#define FN_NODE_RANDOM_FLOAT 1206
/** \} */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 8d7cb90fb71..91693abd1cf 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -4352,6 +4352,8 @@ static void registerSimulationNodes(void)
register_node_type_sim_emit_particles();
register_node_type_sim_time();
register_node_type_sim_particle_attribute();
+ register_node_type_sim_age_reached_event();
+ register_node_type_sim_kill_particle();
}
static void registerFunctionNodes(void)
@@ -4362,6 +4364,7 @@ static void registerFunctionNodes(void)
register_node_type_fn_group_instance_id();
register_node_type_fn_combine_strings();
register_node_type_fn_object_transforms();
+ register_node_type_fn_random_float();
}
void init_nodesystem(void)
diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc
index 4686e217911..8f7f41be079 100644
--- a/source/blender/functions/intern/attributes_ref.cc
+++ b/source/blender/functions/intern/attributes_ref.cc
@@ -27,6 +27,10 @@ AttributesInfoBuilder::~AttributesInfoBuilder()
bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value)
{
+ if (name.size() == 0) {
+ std::cout << "Warning: Tried to add an attribute with empty name.\n";
+ return false;
+ }
if (names_.add_as(name)) {
types_.append(&type);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index c53e01ac80f..33b95d50cc0 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -136,6 +136,7 @@ set(SRC
function/nodes/node_fn_float_compare.cc
function/nodes/node_fn_group_instance_id.cc
function/nodes/node_fn_object_transforms.cc
+ function/nodes/node_fn_random_float.cc
function/nodes/node_fn_switch.cc
function/node_function_util.cc
@@ -232,10 +233,12 @@ set(SRC
shader/node_shader_tree.c
shader/node_shader_util.c
+ simulation/nodes/node_sim_age_reached_event.cc
simulation/nodes/node_sim_common.cc
simulation/nodes/node_sim_emit_particles.cc
simulation/nodes/node_sim_execute_condition.cc
simulation/nodes/node_sim_force.cc
+ simulation/nodes/node_sim_kill_particle.cc
simulation/nodes/node_sim_multi_execute.cc
simulation/nodes/node_sim_particle_attribute.cc
simulation/nodes/node_sim_particle_birth_event.cc
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index 4c05da694f7..1d22e9c6811 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -27,6 +27,7 @@ void register_node_type_fn_switch(void);
void register_node_type_fn_group_instance_id(void);
void register_node_type_fn_combine_strings(void);
void register_node_type_fn_object_transforms(void);
+void register_node_type_fn_random_float(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_simulation.h b/source/blender/nodes/NOD_simulation.h
index 2947d38fe83..fe3f73517ec 100644
--- a/source/blender/nodes/NOD_simulation.h
+++ b/source/blender/nodes/NOD_simulation.h
@@ -39,6 +39,8 @@ void register_node_type_sim_particle_mesh_collision_event(void);
void register_node_type_sim_emit_particles(void);
void register_node_type_sim_time(void);
void register_node_type_sim_particle_attribute(void);
+void register_node_type_sim_age_reached_event(void);
+void register_node_type_sim_kill_particle(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 31ce3f81450..7922a73902c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -270,6 +270,8 @@ DefNode(SimulationNode, SIM_NODE_PARTICLE_MESH_COLLISION_EVENT, 0, "PARTIC
DefNode(SimulationNode, SIM_NODE_EMIT_PARTICLES, 0, "EMIT_PARTICLES", EmitParticles, "Emit Particles", "")
DefNode(SimulationNode, SIM_NODE_TIME, def_sim_time, "TIME", Time, "Time", "")
DefNode(SimulationNode, SIM_NODE_PARTICLE_ATTRIBUTE, def_sim_particle_attribute, "PARTICLE_ATTRIBUTE", ParticleAttribute, "Particle Attribute", "")
+DefNode(SimulationNode, SIM_NODE_AGE_REACHED_EVENT, 0, "AGE_REACHED_EVENT", AgeReachedEvent, "Age Reached Event", "")
+DefNode(SimulationNode, SIM_NODE_KILL_PARTICLE, 0, "KILL_PARTICLE", KillParticle, "Kill Particle", "")
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
@@ -277,7 +279,7 @@ DefNode(FunctionNode, FN_NODE_SWITCH, def_fn_switch, "SWITCH",
DefNode(FunctionNode, FN_NODE_GROUP_INSTANCE_ID, 0, "GROUP_INSTANCE_ID", GroupInstanceID, "Group Instance ID", "")
DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS", CombineStrings, "Combine Strings", "")
DefNode(FunctionNode, FN_NODE_OBJECT_TRANSFORMS, 0, "OBJECT_TRANSFORMS", ObjectTransforms, "Object Transforms", "")
-
+DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
/* undefine macros */
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
new file mode 100644
index 00000000000..2ee0830637a
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -0,0 +1,89 @@
+/*
+ * 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 "node_function_util.hh"
+
+#include "BLI_hash.h"
+
+static bNodeSocketTemplate fn_node_random_float_in[] = {
+ {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_INT, N_("Seed")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_random_float_out[] = {
+ {SOCK_FLOAT, N_("Value")},
+ {-1, ""},
+};
+
+class RandomFloatFunction : public blender::fn::MultiFunction {
+ private:
+ uint32_t function_seed_;
+
+ public:
+ RandomFloatFunction(uint32_t function_seed) : function_seed_(function_seed)
+ {
+ blender::fn::MFSignatureBuilder signature = this->get_builder("Random float");
+ signature.single_input<float>("Min");
+ signature.single_input<float>("Max");
+ signature.single_input<int>("Seed");
+ signature.single_output<float>("Value");
+ }
+
+ void call(blender::IndexMask mask,
+ blender::fn::MFParams params,
+ blender::fn::MFContext UNUSED(context)) const override
+ {
+ blender::fn::VSpan<float> min_values = params.readonly_single_input<float>(0, "Min");
+ blender::fn::VSpan<float> max_values = params.readonly_single_input<float>(1, "Max");
+ blender::fn::VSpan<int> seeds = params.readonly_single_input<int>(2, "Seed");
+ blender::MutableSpan<float> values = params.uninitialized_single_output<float>(3, "Value");
+
+ for (int64_t i : mask) {
+ const float min_value = min_values[i];
+ const float max_value = max_values[i];
+ const int seed = seeds[i];
+ const float value = BLI_hash_int_01((uint32_t)seed ^ function_seed_);
+ values[i] = value * (max_value - min_value) + min_value;
+ }
+ }
+};
+
+static void fn_node_random_float_expand_in_mf_network(
+ blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ uint32_t function_seed = 1746872341u;
+ const blender::nodes::DNode &node = builder.dnode();
+ const blender::DefaultHash<blender::StringRefNull> hasher;
+ function_seed = 33 * function_seed + hasher(node.name());
+ for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr;
+ parent = parent->parent()) {
+ function_seed = 33 * function_seed + hasher(parent->node_ref().name());
+ }
+
+ builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed);
+}
+
+void register_node_type_fn_random_float()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_FLOAT, "Random Float", 0, 0);
+ node_type_socket_templates(&ntype, fn_node_random_float_in, fn_node_random_float_out);
+ ntype.expand_in_mf_network = fn_node_random_float_expand_in_mf_network;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_age_reached_event.cc b/source/blender/nodes/simulation/nodes/node_sim_age_reached_event.cc
new file mode 100644
index 00000000000..add8c4eba4d
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_age_reached_event.cc
@@ -0,0 +1,38 @@
+/*
+ * 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 "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_age_reached_event_in[] = {
+ {SOCK_FLOAT, N_("Age"), 3, 0, 0, 0, 0, 10000000},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_age_reached_event_out[] = {
+ {SOCK_EVENTS, N_("Event")},
+ {-1, ""},
+};
+
+void register_node_type_sim_age_reached_event()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_AGE_REACHED_EVENT, "Age Reached Event", 0, 0);
+ node_type_socket_templates(
+ &ntype, sim_node_age_reached_event_in, sim_node_age_reached_event_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_kill_particle.cc b/source/blender/nodes/simulation/nodes/node_sim_kill_particle.cc
new file mode 100644
index 00000000000..793b40d9365
--- /dev/null
+++ b/source/blender/nodes/simulation/nodes/node_sim_kill_particle.cc
@@ -0,0 +1,36 @@
+/*
+ * 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 "node_simulation_util.h"
+
+static bNodeSocketTemplate sim_node_kill_particle_in[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate sim_node_kill_particle_out[] = {
+ {SOCK_CONTROL_FLOW, N_("Execute")},
+ {-1, ""},
+};
+
+void register_node_type_sim_kill_particle()
+{
+ static bNodeType ntype;
+
+ sim_node_type_base(&ntype, SIM_NODE_KILL_PARTICLE, "Kill Particle", 0, 0);
+ node_type_socket_templates(&ntype, sim_node_kill_particle_in, sim_node_kill_particle_out);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
index 859ad81656b..5e1a6c35d52 100644
--- a/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
+++ b/source/blender/nodes/simulation/nodes/node_sim_particle_mesh_emitter.cc
@@ -21,6 +21,7 @@
static bNodeSocketTemplate sim_node_particle_mesh_emitter_in[] = {
{SOCK_OBJECT, N_("Object")},
{SOCK_FLOAT, N_("Rate"), 100.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX},
+ {SOCK_CONTROL_FLOW, N_("Execute")},
{-1, ""},
};
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.cc b/source/blender/simulation/intern/particle_mesh_emitter.cc
index c1482a29cb7..26541d550eb 100644
--- a/source/blender/simulation/intern/particle_mesh_emitter.cc
+++ b/source/blender/simulation/intern/particle_mesh_emitter.cc
@@ -346,6 +346,16 @@ void ParticleMeshEmitter::emit(ParticleEmitterContext &context) const
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);
+
+ if (action_ != nullptr) {
+ ParticleChunkContext particles{
+ *context.solve_context.state_map.lookup<ParticleSimulationState>(name),
+ IndexRange(amount),
+ attributes,
+ nullptr};
+ ParticleActionContext action_context{context.solve_context, particles};
+ action_->execute(action_context);
+ }
}
}
diff --git a/source/blender/simulation/intern/particle_mesh_emitter.hh b/source/blender/simulation/intern/particle_mesh_emitter.hh
index 601697c9986..724d79c1aec 100644
--- a/source/blender/simulation/intern/particle_mesh_emitter.hh
+++ b/source/blender/simulation/intern/particle_mesh_emitter.hh
@@ -28,14 +28,17 @@ class ParticleMeshEmitter final : public ParticleEmitter {
std::string own_state_name_;
Array<std::string> particle_names_;
const fn::MultiFunction &inputs_fn_;
+ const ParticleAction *action_;
public:
ParticleMeshEmitter(std::string own_state_name,
Array<std::string> particle_names,
- const fn::MultiFunction &inputs_fn)
+ const fn::MultiFunction &inputs_fn,
+ const ParticleAction *action)
: own_state_name_(std::move(own_state_name)),
particle_names_(particle_names),
- inputs_fn_(inputs_fn)
+ inputs_fn_(inputs_fn),
+ action_(action)
{
}
diff --git a/source/blender/simulation/intern/simulation_collect_influences.cc b/source/blender/simulation/intern/simulation_collect_influences.cc
index c309d18c43a..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});
}
@@ -698,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;
}
@@ -718,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;
}
@@ -762,25 +790,38 @@ static void optimize_function_network(CollectContext &context)
class AgeReachedEvent : public ParticleEvent {
private:
std::string attribute_name_;
+ const ParticleFunction &inputs_fn_;
+ const ParticleAction &action_;
public:
- AgeReachedEvent(std::string attribute_name) : attribute_name_(std::move(attribute_name))
+ 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");
- Span<int> has_been_triggered = context.particles.attributes.get<int>(attribute_name_);
- const float age = 5.0f;
+ 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]) {
+ 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 + age;
+ const float trigger_time = birth_time + trigger_age;
if (trigger_time > end_time) {
continue;
}
@@ -795,24 +836,41 @@ class AgeReachedEvent : public ParticleEvent {
void execute(ParticleActionContext &context) const override
{
- MutableSpan<int> dead_states = context.particles.attributes.get<int>("Dead");
MutableSpan<int> has_been_triggered = context.particles.attributes.get<int>(attribute_name_);
for (int i : context.particles.index_mask) {
- dead_states[i] = true;
has_been_triggered[i] = 1;
}
+ action_.execute(context);
}
};
static void collect_age_reached_events(CollectContext &context)
{
- /* TODO: Actually implement an Age Reached Event node. */
- std::string attribute_name = "Has Been Triggered";
- const AgeReachedEvent &event = context.resources.construct<AgeReachedEvent>(AT, attribute_name);
- for (const DNode *dnode : context.particle_simulation_nodes) {
- StringRefNull name = get_identifier(context, *dnode);
- context.influences.particle_events.add_as(name, &event);
- context.influences.particle_attributes_builder.lookup_as(name)->add<int>(attribute_name, 0);
+ 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);
+ }
+ }
}
}
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc
index 9f2766aa24f..d53ccd2bd49 100644
--- a/source/blender/simulation/intern/simulation_solver.cc
+++ b/source/blender/simulation/intern/simulation_solver.cc
@@ -143,8 +143,9 @@ BLI_NOINLINE static void find_next_event_per_particle(
r_next_event_indices.fill_indices(particles.index_mask, -1);
r_time_factors_to_next_event.fill_indices(particles.index_mask, 1.0f);
- Array<float> time_factors(particles.index_mask.min_array_size(), -1.0f);
+ Array<float> time_factors(particles.index_mask.min_array_size());
for (int event_index : events.index_range()) {
+ time_factors.fill(-1.0f);
ParticleEventFilterContext event_context{solve_context, particles, time_factors};
const ParticleEvent &event = *events[event_index];
event.filter(event_context);