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/simulations/bparticles/events.cpp')
-rw-r--r--source/blender/simulations/bparticles/events.cpp155
1 files changed, 155 insertions, 0 deletions
diff --git a/source/blender/simulations/bparticles/events.cpp b/source/blender/simulations/bparticles/events.cpp
new file mode 100644
index 00000000000..c66179cc6f1
--- /dev/null
+++ b/source/blender/simulations/bparticles/events.cpp
@@ -0,0 +1,155 @@
+#include "BLI_hash.h"
+#include "BLI_utildefines.h"
+
+#include "events.hpp"
+
+namespace BParticles {
+
+/* Age Reached Event
+ ******************************************/
+
+void AgeReachedEvent::filter(EventFilterInterface &interface)
+{
+ AttributesRef attributes = interface.attributes();
+
+ ParticleFunctionEvaluator inputs{m_inputs_fn, interface.mask(), interface.attributes()};
+ inputs.context_builder().set_buffer_cache(interface.buffer_cache());
+ inputs.compute();
+
+ float end_time = interface.step_end_time();
+ auto birth_times = attributes.get<float>("Birth Time");
+ auto was_activated_before = attributes.get<bool>(m_is_triggered_attribute);
+
+ for (uint pindex : interface.mask()) {
+ if (was_activated_before[pindex]) {
+ continue;
+ }
+
+ float trigger_age = inputs.get_single<float>("Age", 0, pindex);
+ float birth_time = birth_times[pindex];
+ float age_at_end = end_time - birth_time;
+
+ if (age_at_end >= trigger_age) {
+ FloatInterval time_span = interface.time_span(pindex);
+
+ float age_at_start = age_at_end - time_span.size();
+ if (trigger_age < age_at_start) {
+ interface.trigger_particle(pindex, 0.0f);
+ }
+ else {
+ float time_factor = time_span.safe_factor_of(birth_time + trigger_age);
+ CLAMP(time_factor, 0.0f, 1.0f);
+ interface.trigger_particle(pindex, time_factor);
+ }
+ }
+ }
+}
+
+void AgeReachedEvent::execute(EventExecuteInterface &interface)
+{
+ auto was_activated_before = interface.attributes().get<bool>(m_is_triggered_attribute);
+ for (uint pindex : interface.pindices()) {
+ was_activated_before[pindex] = true;
+ }
+
+ m_action.execute_from_event(interface);
+}
+
+/* Custom Event
+ ***********************************************/
+
+void CustomEvent::filter(EventFilterInterface &interface)
+{
+ FN::EventFilterEndTimeContext end_time_context = {interface.step_end_time()};
+ FN::EventFilterDurationsContext durations_context = {interface.remaining_durations()};
+
+ ParticleFunctionEvaluator inputs{m_inputs_fn, interface.mask(), interface.attributes()};
+ FN::MFContextBuilder &context_builder = inputs.context_builder();
+ context_builder.set_buffer_cache(interface.buffer_cache());
+ context_builder.add_global_context(end_time_context);
+ context_builder.add_element_context(durations_context,
+ FN::MFElementContextIndices::FromDirectMapping());
+ inputs.compute();
+
+ for (uint pindex : interface.mask()) {
+ bool condition = inputs.get_single<bool>("Condition", 0, pindex);
+ if (condition) {
+ float time_factor = inputs.get_single<float>("Time Factor", 1, pindex);
+ time_factor = std::min(std::max(time_factor, 0.0f), 1.0f);
+ interface.trigger_particle(pindex, time_factor);
+ }
+ }
+}
+
+void CustomEvent::execute(EventExecuteInterface &interface)
+{
+ m_action.execute_from_event(interface);
+}
+
+/* Collision Event
+ ***********************************************/
+
+void MeshCollisionEvent::filter(EventFilterInterface &interface)
+{
+ AttributesRef attributes = interface.attributes();
+ auto positions = attributes.get<float3>("Position");
+ auto last_collision_step = attributes.get<int32_t>(m_last_collision_attribute);
+ auto position_offsets = interface.attribute_offsets().get<float3>("Position");
+
+ uint current_update_index = interface.simulation_state().time().current_update_index();
+
+ for (uint pindex : interface.mask()) {
+ if (last_collision_step[pindex] == current_update_index) {
+ continue;
+ }
+
+ float3 world_ray_start = positions[pindex];
+ float3 world_ray_direction = position_offsets[pindex];
+ float3 world_ray_end = world_ray_start + world_ray_direction;
+
+ float3 local_ray_start = m_world_to_local_begin.transform_position(world_ray_start);
+ float3 local_ray_end = m_world_to_local_end.transform_position(world_ray_end);
+ float3 local_ray_direction = local_ray_end - local_ray_start;
+ float local_ray_length = local_ray_direction.normalize_and_get_length();
+
+ auto result = this->ray_cast(local_ray_start, local_ray_direction, local_ray_length);
+ if (result.success) {
+ float time_factor = result.distance / local_ray_length;
+ interface.trigger_particle(pindex, time_factor);
+ if (float3::dot(result.normal, local_ray_direction) > 0) {
+ result.normal = -result.normal;
+ }
+ }
+ }
+}
+
+MeshCollisionEvent::RayCastResult MeshCollisionEvent::ray_cast(float3 start,
+ float3 normalized_direction,
+ float max_distance)
+{
+ BVHTreeRayHit hit;
+ hit.dist = max_distance;
+ hit.index = -1;
+ BLI_bvhtree_ray_cast(m_bvhtree_data.tree,
+ start,
+ normalized_direction,
+ 0.0f,
+ &hit,
+ m_bvhtree_data.raycast_callback,
+ (void *)&m_bvhtree_data);
+
+ return {hit.index >= 0, hit.index, float3(hit.no), hit.dist};
+}
+
+void MeshCollisionEvent::execute(EventExecuteInterface &interface)
+{
+ auto last_collision_step = interface.attributes().get<int32_t>(m_last_collision_attribute);
+ uint current_update_index = interface.simulation_state().time().current_update_index();
+
+ for (uint pindex : interface.pindices()) {
+ last_collision_step[pindex] = current_update_index;
+ }
+ m_action.execute_from_event(interface);
+}
+
+} // namespace BParticles