diff options
Diffstat (limited to 'source/blender/simulation/intern/simulation_solver.cc')
-rw-r--r-- | source/blender/simulation/intern/simulation_solver.cc | 522 |
1 files changed, 0 insertions, 522 deletions
diff --git a/source/blender/simulation/intern/simulation_solver.cc b/source/blender/simulation/intern/simulation_solver.cc deleted file mode 100644 index d53ccd2bd49..00000000000 --- a/source/blender/simulation/intern/simulation_solver.cc +++ /dev/null @@ -1,522 +0,0 @@ -/* - * 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 "simulation_solver.hh" - -#include "BKE_customdata.h" -#include "BKE_persistent_data_handle.hh" - -#include "BLI_rand.hh" -#include "BLI_set.hh" - -#include "DEG_depsgraph_query.h" - -namespace blender::sim { - -static CustomDataType cpp_to_custom_data_type(const CPPType &type) -{ - if (type.is<float3>()) { - return CD_PROP_FLOAT3; - } - if (type.is<float>()) { - return CD_PROP_FLOAT; - } - if (type.is<int32_t>()) { - return CD_PROP_INT32; - } - BLI_assert(false); - return CD_PROP_FLOAT; -} - -static const CPPType &custom_to_cpp_data_type(CustomDataType type) -{ - switch (type) { - case CD_PROP_FLOAT3: - return CPPType::get<float3>(); - case CD_PROP_FLOAT: - return CPPType::get<float>(); - case CD_PROP_INT32: - return CPPType::get<int32_t>(); - default: - BLI_assert(false); - return CPPType::get<float>(); - } -} - -class CustomDataAttributesRef { - private: - Array<void *> buffers_; - int64_t size_; - const AttributesInfo &info_; - - public: - CustomDataAttributesRef(CustomData &custom_data, int64_t size, const AttributesInfo &info) - : buffers_(info.size(), nullptr), size_(size), info_(info) - { - for (int attribute_index : info.index_range()) { - StringRefNull name = info.name_of(attribute_index); - const CPPType &cpp_type = info.type_of(attribute_index); - CustomDataType custom_type = cpp_to_custom_data_type(cpp_type); - void *data = CustomData_get_layer_named(&custom_data, custom_type, name.c_str()); - buffers_[attribute_index] = data; - } - } - - operator MutableAttributesRef() - { - return MutableAttributesRef(info_, buffers_, size_); - } - - operator AttributesRef() const - { - return AttributesRef(info_, buffers_, size_); - } -}; - -static void ensure_attributes_exist(ParticleSimulationState *state, const AttributesInfo &info) -{ - bool found_layer_to_remove; - do { - found_layer_to_remove = false; - for (int layer_index = 0; layer_index < state->attributes.totlayer; layer_index++) { - CustomDataLayer *layer = &state->attributes.layers[layer_index]; - BLI_assert(layer->name != nullptr); - const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer->type); - StringRefNull name = layer->name; - if (!info.has_attribute(name, cpp_type)) { - found_layer_to_remove = true; - CustomData_free_layer(&state->attributes, layer->type, state->tot_particles, layer_index); - break; - } - } - } while (found_layer_to_remove); - - for (int attribute_index : info.index_range()) { - StringRefNull attribute_name = info.name_of(attribute_index); - const CPPType &cpp_type = info.type_of(attribute_index); - CustomDataType custom_type = cpp_to_custom_data_type(cpp_type); - if (CustomData_get_layer_named(&state->attributes, custom_type, attribute_name.c_str()) == - nullptr) { - void *data = CustomData_add_layer_named(&state->attributes, - custom_type, - CD_CALLOC, - nullptr, - state->tot_particles, - attribute_name.c_str()); - cpp_type.fill_uninitialized(info.default_of(attribute_index), data, state->tot_particles); - } - } -} - -BLI_NOINLINE static void apply_remaining_diffs(ParticleChunkContext &context) -{ - BLI_assert(context.integration != nullptr); - MutableSpan<float3> positions = context.attributes.get<float3>("Position"); - MutableSpan<float3> velocities = context.attributes.get<float3>("Velocity"); - - for (int i : context.index_mask) { - positions[i] += context.integration->position_diffs[i]; - velocities[i] += context.integration->velocity_diffs[i]; - } -} - -BLI_NOINLINE static void find_next_event_per_particle( - SimulationSolveContext &solve_context, - ParticleChunkContext &particles, - Span<const ParticleEvent *> events, - MutableSpan<int> r_next_event_indices, - MutableSpan<float> r_time_factors_to_next_event) -{ - 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()); - 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); - - for (int i : particles.index_mask) { - const float time_factor = time_factors[i]; - const float previously_smallest_time_factor = r_time_factors_to_next_event[i]; - if (time_factor >= 0.0f && time_factor <= previously_smallest_time_factor) { - r_time_factors_to_next_event[i] = time_factor; - r_next_event_indices[i] = event_index; - } - } - } -} - -BLI_NOINLINE static void forward_particles_to_next_event_or_end( - ParticleChunkContext &particles, Span<float> time_factors_to_next_event) -{ - MutableSpan<float3> positions = particles.attributes.get<float3>("Position"); - MutableSpan<float3> velocities = particles.attributes.get<float3>("Velocity"); - - MutableSpan<float3> position_diffs = particles.integration->position_diffs; - MutableSpan<float3> velocity_diffs = particles.integration->velocity_diffs; - MutableSpan<float> durations = particles.integration->durations; - - for (int i : particles.index_mask) { - const float time_factor = time_factors_to_next_event[i]; - positions[i] += position_diffs[i] * time_factor; - velocities[i] += velocity_diffs[i] * time_factor; - - const float remaining_time_factor = 1.0f - time_factor; - position_diffs[i] *= remaining_time_factor; - velocity_diffs[i] *= remaining_time_factor; - durations[i] *= remaining_time_factor; - } -} - -BLI_NOINLINE static void group_particles_by_event( - IndexMask mask, - Span<int> next_event_indices, - MutableSpan<Vector<int64_t>> r_particles_per_event) -{ - for (int i : mask) { - int event_index = next_event_indices[i]; - if (event_index >= 0) { - r_particles_per_event[event_index].append(i); - } - } -} - -BLI_NOINLINE static void execute_events(SimulationSolveContext &solve_context, - ParticleChunkContext &all_particles, - Span<const ParticleEvent *> events, - Span<Vector<int64_t>> particles_per_event) -{ - for (int event_index : events.index_range()) { - Span<int64_t> pindices = particles_per_event[event_index]; - if (pindices.is_empty()) { - continue; - } - - const ParticleEvent &event = *events[event_index]; - ParticleChunkContext particles{ - all_particles.state, pindices, all_particles.attributes, all_particles.integration}; - ParticleActionContext action_context{solve_context, particles}; - event.execute(action_context); - } -} - -BLI_NOINLINE static void find_unfinished_particles(IndexMask index_mask, - Span<float> time_factors_to_next_event, - Vector<int64_t> &r_unfinished_pindices) -{ - for (int i : index_mask) { - float time_factor = time_factors_to_next_event[i]; - if (time_factor < 1.0f) { - r_unfinished_pindices.append(i); - } - } -} - -BLI_NOINLINE static void simulate_to_next_event(SimulationSolveContext &solve_context, - ParticleChunkContext &particles, - Span<const ParticleEvent *> events, - Vector<int64_t> &r_unfinished_pindices) -{ - int array_size = particles.index_mask.min_array_size(); - Array<int> next_event_indices(array_size); - Array<float> time_factors_to_next_event(array_size); - - find_next_event_per_particle( - solve_context, particles, events, next_event_indices, time_factors_to_next_event); - - forward_particles_to_next_event_or_end(particles, time_factors_to_next_event); - - Array<Vector<int64_t>> particles_per_event(events.size()); - group_particles_by_event(particles.index_mask, next_event_indices, particles_per_event); - - execute_events(solve_context, particles, events, particles_per_event); - find_unfinished_particles( - particles.index_mask, time_factors_to_next_event, r_unfinished_pindices); -} - -BLI_NOINLINE static void simulate_with_max_n_events(SimulationSolveContext &solve_context, - ParticleSimulationState &state, - ParticleChunkContext &particles, - int max_events) -{ - Span<const ParticleEvent *> events = solve_context.influences.particle_events.lookup_as( - state.head.name); - if (events.size() == 0) { - apply_remaining_diffs(particles); - return; - } - - Vector<int64_t> unfininished_pindices = particles.index_mask.indices(); - for (int iteration : IndexRange(max_events)) { - UNUSED_VARS(iteration); - if (unfininished_pindices.is_empty()) { - break; - } - - Vector<int64_t> new_unfinished_pindices; - ParticleChunkContext remaining_particles{particles.state, - unfininished_pindices.as_span(), - particles.attributes, - particles.integration}; - simulate_to_next_event(solve_context, remaining_particles, events, new_unfinished_pindices); - unfininished_pindices = std::move(new_unfinished_pindices); - } - - if (!unfininished_pindices.is_empty()) { - ParticleChunkContext remaining_particles{particles.state, - unfininished_pindices.as_span(), - particles.attributes, - particles.integration}; - apply_remaining_diffs(remaining_particles); - } -} - -BLI_NOINLINE static void simulate_particle_chunk(SimulationSolveContext &solve_context, - ParticleSimulationState &state, - MutableAttributesRef attributes, - MutableSpan<float> remaining_durations, - float end_time) -{ - int particle_amount = attributes.size(); - - Span<const ParticleAction *> begin_actions = - solve_context.influences.particle_time_step_begin_actions.lookup_as(state.head.name); - for (const ParticleAction *action : begin_actions) { - ParticleChunkContext particles{state, IndexMask(particle_amount), attributes}; - ParticleActionContext action_context{solve_context, particles}; - action->execute(action_context); - } - - Array<float3> force_vectors{particle_amount, {0, 0, 0}}; - Span<const ParticleForce *> forces = solve_context.influences.particle_forces.lookup_as( - state.head.name); - for (const ParticleForce *force : forces) { - ParticleChunkContext particles{state, IndexMask(particle_amount), attributes}; - ParticleForceContext particle_force_context{solve_context, particles, force_vectors}; - force->add_force(particle_force_context); - } - - MutableSpan<float3> velocities = attributes.get<float3>("Velocity"); - - Array<float3> position_diffs(particle_amount); - Array<float3> velocity_diffs(particle_amount); - for (int i : IndexRange(particle_amount)) { - const float time_step = remaining_durations[i]; - velocity_diffs[i] = force_vectors[i] * time_step; - position_diffs[i] = (velocities[i] + velocity_diffs[i] / 2.0f) * time_step; - } - - ParticleChunkIntegrationContext integration_context = { - position_diffs, velocity_diffs, remaining_durations, end_time}; - ParticleChunkContext particle_chunk_context{ - state, IndexMask(particle_amount), attributes, &integration_context}; - - simulate_with_max_n_events(solve_context, state, particle_chunk_context, 10); - - Span<const ParticleAction *> end_actions = - solve_context.influences.particle_time_step_end_actions.lookup_as(state.head.name); - for (const ParticleAction *action : end_actions) { - ParticleChunkContext particles{state, IndexMask(particle_amount), attributes}; - ParticleActionContext action_context{solve_context, particles}; - action->execute(action_context); - } -} - -BLI_NOINLINE static void simulate_existing_particles(SimulationSolveContext &solve_context, - ParticleSimulationState &state, - const AttributesInfo &attributes_info) -{ - CustomDataAttributesRef custom_data_attributes{ - state.attributes, state.tot_particles, attributes_info}; - MutableAttributesRef attributes = custom_data_attributes; - - Array<float> remaining_durations(state.tot_particles, solve_context.solve_interval.duration()); - simulate_particle_chunk( - solve_context, state, attributes, remaining_durations, solve_context.solve_interval.stop()); -} - -BLI_NOINLINE static void run_emitters(SimulationSolveContext &solve_context, - ParticleAllocators &particle_allocators) -{ - for (const ParticleEmitter *emitter : solve_context.influences.particle_emitters) { - ParticleEmitterContext emitter_context{ - solve_context, particle_allocators, solve_context.solve_interval}; - emitter->emit(emitter_context); - } -} - -BLI_NOINLINE static int count_particles_after_time_step(ParticleSimulationState &state, - ParticleAllocator &allocator) -{ - CustomDataAttributesRef custom_data_attributes{ - state.attributes, state.tot_particles, allocator.attributes_info()}; - MutableAttributesRef attributes = custom_data_attributes; - int new_particle_amount = attributes.get<int>("Dead").count(0); - - for (MutableAttributesRef emitted_attributes : allocator.get_allocations()) { - new_particle_amount += emitted_attributes.get<int>("Dead").count(0); - } - - return new_particle_amount; -} - -BLI_NOINLINE static void remove_dead_and_add_new_particles(ParticleSimulationState &state, - ParticleAllocator &allocator) -{ - const int new_particle_amount = count_particles_after_time_step(state, allocator); - - CustomDataAttributesRef custom_data_attributes{ - state.attributes, state.tot_particles, allocator.attributes_info()}; - - Vector<MutableAttributesRef> particle_sources; - particle_sources.append(custom_data_attributes); - particle_sources.extend(allocator.get_allocations()); - - CustomDataLayer *dead_layer = nullptr; - - for (CustomDataLayer &layer : MutableSpan(state.attributes.layers, state.attributes.totlayer)) { - StringRefNull name = layer.name; - if (name == "Dead") { - dead_layer = &layer; - continue; - } - const CPPType &cpp_type = custom_to_cpp_data_type((CustomDataType)layer.type); - GMutableSpan new_buffer{ - cpp_type, - MEM_mallocN_aligned(new_particle_amount * cpp_type.size(), cpp_type.alignment(), AT), - new_particle_amount}; - - int current = 0; - for (MutableAttributesRef attributes : particle_sources) { - Span<int> dead_states = attributes.get<int>("Dead"); - GSpan source_buffer = attributes.get(name); - BLI_assert(source_buffer.type() == cpp_type); - for (int i : attributes.index_range()) { - if (dead_states[i] == 0) { - cpp_type.copy_to_uninitialized(source_buffer[i], new_buffer[current]); - current++; - } - } - } - - if (layer.data != nullptr) { - MEM_freeN(layer.data); - } - layer.data = new_buffer.data(); - } - - BLI_assert(dead_layer != nullptr); - if (dead_layer->data != nullptr) { - MEM_freeN(dead_layer->data); - } - dead_layer->data = MEM_callocN(sizeof(int) * new_particle_amount, AT); - - state.tot_particles = new_particle_amount; - state.next_particle_id += allocator.total_allocated(); -} - -void initialize_simulation_states(Simulation &simulation, - Depsgraph &UNUSED(depsgraph), - const SimulationInfluences &UNUSED(influences), - const bke::PersistentDataHandleMap &UNUSED(handle_map)) -{ - simulation.current_simulation_time = 0.0f; -} - -void solve_simulation_time_step(Simulation &simulation, - Depsgraph &depsgraph, - const SimulationInfluences &influences, - const bke::PersistentDataHandleMap &handle_map, - const DependencyAnimations &dependency_animations, - float time_step) -{ - SimulationStateMap state_map; - LISTBASE_FOREACH (SimulationState *, state, &simulation.states) { - state_map.add(state); - } - - SimulationSolveContext solve_context{simulation, - depsgraph, - influences, - TimeInterval(simulation.current_simulation_time, time_step), - state_map, - handle_map, - dependency_animations}; - - Span<ParticleSimulationState *> particle_simulation_states = - state_map.lookup<ParticleSimulationState>(); - - Map<std::string, std::unique_ptr<AttributesInfo>> attribute_infos; - Map<std::string, std::unique_ptr<ParticleAllocator>> particle_allocators_map; - for (ParticleSimulationState *state : particle_simulation_states) { - const AttributesInfoBuilder &builder = *influences.particle_attributes_builder.lookup_as( - state->head.name); - auto info = std::make_unique<AttributesInfo>(builder); - - ensure_attributes_exist(state, *info); - - uint32_t hash_seed = DefaultHash<StringRef>{}(state->head.name); - particle_allocators_map.add_new( - state->head.name, - std::make_unique<ParticleAllocator>(*info, state->next_particle_id, hash_seed)); - attribute_infos.add_new(state->head.name, std::move(info)); - } - - ParticleAllocators particle_allocators{particle_allocators_map}; - - for (ParticleSimulationState *state : particle_simulation_states) { - const AttributesInfo &attributes_info = *attribute_infos.lookup_as(state->head.name); - simulate_existing_particles(solve_context, *state, attributes_info); - } - - run_emitters(solve_context, particle_allocators); - - for (ParticleSimulationState *state : particle_simulation_states) { - ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name); - - for (MutableAttributesRef attributes : allocator.get_allocations()) { - Span<const ParticleAction *> actions = influences.particle_birth_actions.lookup_as( - state->head.name); - for (const ParticleAction *action : actions) { - ParticleChunkContext chunk_context{*state, IndexRange(attributes.size()), attributes}; - ParticleActionContext action_context{solve_context, chunk_context}; - action->execute(action_context); - } - } - } - - for (ParticleSimulationState *state : particle_simulation_states) { - ParticleAllocator &allocator = *particle_allocators.try_get_allocator(state->head.name); - - for (MutableAttributesRef attributes : allocator.get_allocations()) { - Array<float> remaining_durations(attributes.size()); - Span<float> birth_times = attributes.get<float>("Birth Time"); - const float end_time = solve_context.solve_interval.stop(); - for (int i : attributes.index_range()) { - remaining_durations[i] = end_time - birth_times[i]; - } - simulate_particle_chunk(solve_context, *state, attributes, remaining_durations, end_time); - } - - remove_dead_and_add_new_particles(*state, allocator); - } - - simulation.current_simulation_time = solve_context.solve_interval.stop(); -} - -} // namespace blender::sim |