[Bf-blender-cvs] [21b20ae5ec1] master: Particles: initial support for forces in simulation node trees

Jacques Lucke noreply at git.blender.org
Sun Jul 12 12:54:27 CEST 2020


Commit: 21b20ae5ec1512b52f6c231863a278ccacb4835c
Author: Jacques Lucke
Date:   Sun Jul 12 12:38:57 2020 +0200
Branches: master
https://developer.blender.org/rB21b20ae5ec1512b52f6c231863a278ccacb4835c

Particles: initial support for forces in simulation node trees

The force node can now be used to control the behavior of particles.
Forces can access particles attributes. Currently, there are three attributes:
`Position` (vector), `Velocity` (vector) and `ID` (integer).

Supported nodes are: Math, Vector Math, Separate Vector, Combine Vector and Value.

Next, I'll have to split `simulation.cc` into multiple files and move
some stuff out of blenkernel into another folder.

===================================================================

M	source/blender/blenkernel/intern/simulation.cc

===================================================================

diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index cce324d49ee..7792a6c91c6 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -176,6 +176,10 @@ static void ensure_attributes_exist(ParticleSimulationState *state)
     CustomData_add_layer_named(
         &state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Velocity");
   }
+  if (CustomData_get_layer_named(&state->attributes, CD_PROP_INT32, "ID") == nullptr) {
+    CustomData_add_layer_named(
+        &state->attributes, CD_PROP_INT32, CD_CALLOC, nullptr, state->tot_particles, "ID");
+  }
 }
 
 static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow)
@@ -211,11 +215,8 @@ static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulati
   }
 }
 
-using AttributeNodeMap = Map<fn::MFDummyNode *, std::pair<std::string, fn::MFDataType>>;
-
-static AttributeNodeMap deduplicate_attribute_nodes(fn::MFNetwork &network,
-                                                    MFNetworkTreeMap &network_map,
-                                                    const DerivedNodeTree &tree)
+static Map<const fn::MFOutputSocket *, std::string> deduplicate_attribute_nodes(
+    fn::MFNetwork &network, MFNetworkTreeMap &network_map, const DerivedNodeTree &tree)
 {
   Span<const DNode *> attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute");
   uint amount = attribute_dnodes.size();
@@ -251,7 +252,7 @@ static AttributeNodeMap deduplicate_attribute_nodes(fn::MFNetwork &network,
         .append(&name_sockets[i]->node());
   }
 
-  AttributeNodeMap final_attribute_nodes;
+  Map<const fn::MFOutputSocket *, std::string> attribute_inputs;
   for (auto item : attribute_nodes_by_name_and_type.items()) {
     StringRef attribute_name = item.key.first;
     fn::MFDataType data_type = item.key.second;
@@ -264,10 +265,10 @@ static AttributeNodeMap deduplicate_attribute_nodes(fn::MFNetwork &network,
     }
     network.remove(nodes);
 
-    final_attribute_nodes.add_new(&new_attribute_socket.node().as_dummy(), item.key);
+    attribute_inputs.add_new(&new_attribute_socket, attribute_name);
   }
 
-  return final_attribute_nodes;
+  return attribute_inputs;
 }
 
 class CustomDataAttributesRef {
@@ -282,7 +283,16 @@ class CustomDataAttributesRef {
     fn::AttributesInfoBuilder builder;
     for (const CustomDataLayer &layer : Span(custom_data.layers, custom_data.totlayer)) {
       buffers_.append(layer.data);
-      builder.add<float3>(layer.name, {0, 0, 0});
+      switch (layer.type) {
+        case CD_PROP_INT32: {
+          builder.add<int32_t>(layer.name, 0);
+          break;
+        }
+        case CD_LOCATION: {
+          builder.add<float3>(layer.name, {0, 0, 0});
+          break;
+        }
+      }
     }
     info_ = std::make_unique<fn::AttributesInfo>(builder);
     size_ = size;
@@ -386,6 +396,321 @@ static void update_simulation_state_list(Simulation *simulation, const DerivedNo
   add_missing_particle_states(simulation, state_names);
 }
 
+class ParticleFunctionInput {
+ public:
+  virtual ~ParticleFunctionInput() = default;
+  virtual void add_input(fn::AttributesRef attributes,
+                         fn::MFParamsBuilder &params,
+                         ResourceCollector &resources) const = 0;
+};
+
+class ParticleFunction {
+ private:
+  const fn::MultiFunction *global_fn_;
+  const fn::MultiFunction *per_particle_fn_;
+  Array<const ParticleFunctionInput *> global_inputs_;
+  Array<const ParticleFunctionInput *> per_particle_inputs_;
+  Array<bool> output_is_global_;
+  Vector<uint> global_output_indices_;
+  Vector<uint> per_particle_output_indices_;
+  Vector<fn::MFDataType> output_types_;
+  Vector<StringRefNull> output_names_;
+
+  friend class ParticleFunctionEvaluator;
+
+ public:
+  ParticleFunction(const fn::MultiFunction *global_fn,
+                   const fn::MultiFunction *per_particle_fn,
+                   Span<const ParticleFunctionInput *> global_inputs,
+                   Span<const ParticleFunctionInput *> per_particle_inputs,
+                   Span<bool> output_is_global)
+      : global_fn_(global_fn),
+        per_particle_fn_(per_particle_fn),
+        global_inputs_(global_inputs),
+        per_particle_inputs_(per_particle_inputs),
+        output_is_global_(output_is_global)
+  {
+    for (uint i : output_is_global_.index_range()) {
+      if (output_is_global_[i]) {
+        uint param_index = global_inputs_.size() + global_output_indices_.size();
+        fn::MFParamType param_type = global_fn_->param_type(param_index);
+        BLI_assert(param_type.is_output());
+        output_types_.append(param_type.data_type());
+        output_names_.append(global_fn_->param_name(param_index));
+        global_output_indices_.append(i);
+      }
+      else {
+        uint param_index = per_particle_inputs_.size() + per_particle_output_indices_.size();
+        fn::MFParamType param_type = per_particle_fn_->param_type(param_index);
+        BLI_assert(param_type.is_output());
+        output_types_.append(param_type.data_type());
+        output_names_.append(per_particle_fn_->param_name(param_index));
+        per_particle_output_indices_.append(i);
+      }
+    }
+  }
+};
+
+class ParticleFunctionEvaluator {
+ private:
+  ResourceCollector resources_;
+  const ParticleFunction &particle_fn_;
+  IndexMask mask_;
+  fn::MFContextBuilder global_context_;
+  fn::MFContextBuilder per_particle_context_;
+  fn::AttributesRef particle_attributes_;
+  Vector<void *> outputs_;
+  bool is_computed_ = false;
+
+ public:
+  ParticleFunctionEvaluator(const ParticleFunction &particle_fn,
+                            IndexMask mask,
+                            fn::AttributesRef particle_attributes)
+      : particle_fn_(particle_fn),
+        mask_(mask),
+        particle_attributes_(particle_attributes),
+        outputs_(particle_fn_.output_types_.size(), nullptr)
+  {
+  }
+
+  ~ParticleFunctionEvaluator()
+  {
+    for (uint output_index : outputs_.index_range()) {
+      void *buffer = outputs_[output_index];
+      fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+      BLI_assert(data_type.is_single()); /* For now. */
+      const fn::CPPType &type = data_type.single_type();
+
+      if (particle_fn_.output_is_global_[output_index]) {
+        type.destruct(buffer);
+      }
+      else {
+        type.destruct_indices(outputs_[0], mask_);
+      }
+    }
+  }
+
+  void compute()
+  {
+    BLI_assert(!is_computed_);
+    this->compute_globals();
+    this->compute_per_particle();
+    is_computed_ = true;
+  }
+
+  template<typename T> fn::VSpan<T> get(uint output_index, StringRef expected_name) const
+  {
+    return this->get(output_index, expected_name).typed<T>();
+  }
+
+  fn::GVSpan get(uint output_index, StringRef expected_name) const
+  {
+#ifdef DEBUG
+    StringRef real_name = particle_fn_.output_names_[output_index];
+    BLI_assert(expected_name == real_name);
+    BLI_assert(is_computed_);
+#endif
+    const void *buffer = outputs_[output_index];
+    const fn::CPPType &type = particle_fn_.output_types_[output_index].single_type();
+    if (particle_fn_.output_is_global_[output_index]) {
+      return fn::GVSpan::FromSingleWithMaxSize(type, buffer);
+    }
+    else {
+      return fn::GVSpan(fn::GSpan(type, buffer, mask_.min_array_size()));
+    }
+  }
+
+ private:
+  void compute_globals()
+  {
+    if (particle_fn_.global_fn_ == nullptr) {
+      return;
+    }
+
+    fn::MFParamsBuilder params(*particle_fn_.global_fn_, mask_.min_array_size());
+
+    /* Add input parameters. */
+    for (const ParticleFunctionInput *input : particle_fn_.global_inputs_) {
+      input->add_input(particle_attributes_, params, resources_);
+    }
+
+    /* Add output parameters. */
+    for (uint output_index : particle_fn_.global_output_indices_) {
+      fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+      BLI_assert(data_type.is_single()); /* For now. */
+
+      const fn::CPPType &type = data_type.single_type();
+      void *buffer = resources_.linear_allocator().allocate(type.size(), type.alignment());
+      params.add_uninitialized_single_output(fn::GMutableSpan(type, buffer, 1));
+      outputs_[output_index] = buffer;
+    }
+
+    particle_fn_.global_fn_->call({0}, params, global_context_);
+  }
+
+  void compute_per_particle()
+  {
+    if (particle_fn_.per_particle_fn_ == nullptr) {
+      return;
+    }
+
+    fn::MFParamsBuilder params(*particle_fn_.per_particle_fn_, mask_.min_array_size());
+
+    /* Add input parameters. */
+    for (const ParticleFunctionInput *input : particle_fn_.per_particle_inputs_) {
+      input->add_input(particle_attributes_, params, resources_);
+    }
+
+    /* Add output parameters. */
+    for (uint output_index : particle_fn_.per_particle_output_indices_) {
+      fn::MFDataType data_type = particle_fn_.output_types_[output_index];
+      BLI_assert(data_type.is_single()); /* For now. */
+
+      const fn::CPPType &type = data_type.single_type();
+      void *buffer = resources_.linear_allocator().allocate(type.size() * mask_.min_array_size(),
+                                                            type.alignment());
+      params.add_uninitialized_single_output(
+          fn::GMutableSpan(type, buffer, mask_.min_array_size()));
+      outputs_[output_index] = buffer;
+    }
+
+    particle_fn_.per_particle_fn_->call(mask_, params, global_context_);
+  }
+};
+
+class ParticleAttributeInput : public ParticleFunctionInput {
+ private:
+  std::string attribute_name_;
+  const fn::CPPType &attribute_type_;
+
+ public:
+  ParticleAttributeInput(std::string attribute_name, const fn::CPPType &attribute_type)
+      : attribute_name_(std::move(attribute_name)), attribute_type_(attribute_type)
+  {
+  }
+
+  void add_input(fn::AttributesRef attributes,
+                 fn::MFParamsBuilder &params,
+                 ResourceCollector &UNUSED(resources)) const override
+  {
+    std::optional<fn::GSpan> span = attributes.try_get(attribute_name_, attribute_type_);
+    if (span.has_value

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list