[Bf-blender-cvs] [766edbdf1f8] master: Particles: improve mesh emitter

Jacques Lucke noreply at git.blender.org
Thu Jul 23 17:57:42 CEST 2020


Commit: 766edbdf1f82389d89dc708b1e0d36efeaba0888
Author: Jacques Lucke
Date:   Thu Jul 23 17:57:11 2020 +0200
Branches: master
https://developer.blender.org/rB766edbdf1f82389d89dc708b1e0d36efeaba0888

Particles: improve mesh emitter

Particles are now emitted from vertices of the mesh.

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

M	source/blender/blenlib/BLI_vector.hh
M	source/blender/functions/FN_multi_function_params.hh
M	source/blender/simulation/CMakeLists.txt
A	source/blender/simulation/intern/particle_mesh_emitter.cc
A	source/blender/simulation/intern/particle_mesh_emitter.hh
M	source/blender/simulation/intern/simulation_collect_influences.cc
M	source/blender/simulation/intern/simulation_collect_influences.hh
M	source/blender/simulation/intern/simulation_solver.cc
M	source/blender/simulation/intern/simulation_solver.hh
A	source/blender/simulation/intern/simulation_solver_influences.hh
M	source/blender/simulation/intern/time_interval.hh

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

diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 1bb674093bb..7eac511bf4a 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -561,7 +561,7 @@ class Vector {
 
   /**
    * Return a reference to the last element in the vector.
-   * This will assert when the vector is empty.
+   * This invokes undefined behavior when the vector is empty.
    */
   const T &last() const
   {
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 93d7b47af83..ac4dca33cf0 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -50,52 +50,56 @@ class MFParamsBuilder {
 
   MFParamsBuilder(const class MultiFunction &fn, int64_t min_array_size);
 
-  template<typename T> void add_readonly_single_input(const T *value)
+  template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
   {
-    this->add_readonly_single_input(GVSpan::FromSingle(CPPType::get<T>(), value, min_array_size_));
+    this->add_readonly_single_input(GVSpan::FromSingle(CPPType::get<T>(), value, min_array_size_),
+                                    expected_name);
   }
-  void add_readonly_single_input(GVSpan ref)
+  void add_readonly_single_input(GVSpan ref, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()));
+    this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name);
     BLI_assert(ref.size() >= min_array_size_);
     virtual_spans_.append(ref);
   }
 
-  void add_readonly_vector_input(GVArraySpan ref)
+  void add_readonly_vector_input(GVArraySpan ref, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()));
+    this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name);
     BLI_assert(ref.size() >= min_array_size_);
     virtual_array_spans_.append(ref);
   }
 
-  template<typename T> void add_uninitialized_single_output(T *value)
+  template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "")
   {
-    this->add_uninitialized_single_output(GMutableSpan(CPPType::get<T>(), value, 1));
+    this->add_uninitialized_single_output(GMutableSpan(CPPType::get<T>(), value, 1),
+                                          expected_name);
   }
-  void add_uninitialized_single_output(GMutableSpan ref)
+  void add_uninitialized_single_output(GMutableSpan ref, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()));
+    this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()), expected_name);
     BLI_assert(ref.size() >= min_array_size_);
     mutable_spans_.append(ref);
   }
 
-  void add_vector_output(GVectorArray &vector_array)
+  void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()));
+    this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()),
+                                    expected_name);
     BLI_assert(vector_array.size() >= min_array_size_);
     vector_arrays_.append(&vector_array);
   }
 
-  void add_single_mutable(GMutableSpan ref)
+  void add_single_mutable(GMutableSpan ref, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()));
+    this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()), expected_name);
     BLI_assert(ref.size() >= min_array_size_);
     mutable_spans_.append(ref);
   }
 
-  void add_vector_mutable(GVectorArray &vector_array)
+  void add_vector_mutable(GVectorArray &vector_array, StringRef expected_name = "")
   {
-    this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()));
+    this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()),
+                                    expected_name);
     BLI_assert(vector_array.size() >= min_array_size_);
     vector_arrays_.append(&vector_array);
   }
@@ -119,11 +123,17 @@ class MFParamsBuilder {
   }
 
  private:
-  void assert_current_param_type(MFParamType param_type)
+  void assert_current_param_type(MFParamType param_type, StringRef expected_name = "")
   {
-    UNUSED_VARS_NDEBUG(param_type);
+    UNUSED_VARS_NDEBUG(param_type, expected_name);
 #ifdef DEBUG
     int param_index = this->current_param_index();
+
+    if (expected_name != "") {
+      StringRef actual_name = signature_->param_names[param_index];
+      BLI_assert(actual_name == expected_name);
+    }
+
     MFParamType expected_type = signature_->param_types[param_index];
     BLI_assert(expected_type == param_type);
 #endif
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/intern/particle_mesh_emitter.cc b/source/blender/simulation/intern/particle_mesh_emitter.cc
new file mode 100644
index 00000000000..ab2ee0c81ed
--- /dev/null
+++ b/source/blender/simulation/intern/particle_mesh_emitter.cc
@@ -0,0 +1,147 @@
+/*
+ * 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 "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+namespace blender::sim {
+
+struct EmitterSettings {
+  const Object *object;
+  float rate;
+};
+
+static 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 void 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;
+  }
+  if (settings.rate <= 0.000001f) {
+    return;
+  }
+  if (settings.object->type != OB_MESH) {
+    return;
+  }
+  const Mesh &mesh = *(Mesh *)settings.object->data;
+  if (mesh.totvert == 0) {
+    return;
+  }
+
+  float4x4 local_to_world = settings.object->obmat;
+
+  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);
+  if (r_birth_times.is_empty()) {
+    return;
+  }
+
+  state.last_birth_time = r_birth_times.last();
+
+  for (int i : r_birth_times.index_range()) {
+    UNUSED_VARS(i);
+    const int vertex_index = rng.get_int32() % mesh.totvert;
+    float3 vertex_position = mesh.mvert[vertex_index].co;
+    r_positions.append(local_to_world * vertex_position);
+    r_velocities.append(rng.get_unit_float3());
+  }
+}
+
+static 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;
+

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list