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:
authorJacques Lucke <jacques@blender.org>2020-07-09 16:40:27 +0300
committerJacques Lucke <jacques@blender.org>2020-07-09 16:40:27 +0300
commit580d50091cfb0467cbde165058a6e78ef4898045 (patch)
treef123808f3397df3a273f991e9e3239e603d68ce0 /source/blender/blenkernel/intern/simulation.cc
parent31ad43a3c7dde771cb6d92b6d20bf7b2e3f2bed6 (diff)
Particles: Create a simulation state for every Particle Simulation node
Every Particle Simulation node has a name (or a path when it is in a node group). This name has to be used in the Simulation modifier on a point cloud to see the particles. Caching has been disabled for now, because it was holding back development a bit. To reset the simulation, go back to frame 1. Currently, there is no way to influence the simulation. There are just some randomly moving points. Changing that is the next step.
Diffstat (limited to 'source/blender/blenkernel/intern/simulation.cc')
-rw-r--r--source/blender/blenkernel/intern/simulation.cc366
1 files changed, 287 insertions, 79 deletions
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index c4a35141b0d..35ef664dce3 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -31,6 +31,7 @@
#include "BLI_float3.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -44,6 +45,7 @@
#include "BKE_lib_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_multi_function.hh"
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
@@ -51,9 +53,18 @@
#include "BLT_translation.h"
+#include "FN_attributes_ref.hh"
+#include "FN_cpp_types.hh"
+#include "FN_multi_function_network_evaluation.hh"
+#include "FN_multi_function_network_optimization.hh"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+extern "C" {
+void WM_clipboard_text_set(const char *buf, bool selection);
+}
+
static void simulation_init_data(ID *id)
{
Simulation *simulation = (Simulation *)id;
@@ -63,14 +74,6 @@ static void simulation_init_data(ID *id)
bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
simulation->nodetree = ntree;
-
- /* Add a default particle simulation state for now. */
- ParticleSimulationState *state = (ParticleSimulationState *)MEM_callocN(
- sizeof(ParticleSimulationState), __func__);
- CustomData_reset(&state->attributes);
-
- state->point_cache = BKE_ptcache_add(&state->ptcaches);
- BLI_addtail(&simulation->states, state);
}
static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag)
@@ -89,19 +92,19 @@ static void simulation_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons
}
BLI_listbase_clear(&simulation_dst->states);
+}
- LISTBASE_FOREACH (const SimulationState *, state_src, &simulation_src->states) {
- switch ((eSimulationStateType)state_src->type) {
- case SIM_STATE_TYPE_PARTICLES: {
- ParticleSimulationState *particle_state_dst = (ParticleSimulationState *)MEM_callocN(
- sizeof(ParticleSimulationState), __func__);
- CustomData_reset(&particle_state_dst->attributes);
+static void free_simulation_state_head(SimulationState *state)
+{
+ MEM_freeN(state->name);
+}
- BLI_addtail(&simulation_dst->states, particle_state_dst);
- break;
- }
- }
- }
+static void free_particle_simulation_state(ParticleSimulationState *state)
+{
+ free_simulation_state_head(&state->head);
+ CustomData_free(&state->attributes, state->tot_particles);
+ BKE_ptcache_free_list(&state->ptcaches);
+ MEM_freeN(state);
}
static void simulation_free_data(ID *id)
@@ -119,13 +122,10 @@ static void simulation_free_data(ID *id)
LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) {
switch ((eSimulationStateType)state->type) {
case SIM_STATE_TYPE_PARTICLES: {
- ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
- CustomData_free(&particle_state->attributes, particle_state->tot_particles);
- BKE_ptcache_free_list(&particle_state->ptcaches);
+ free_particle_simulation_state((ParticleSimulationState *)state);
break;
}
}
- MEM_freeN(state);
}
}
@@ -166,59 +166,230 @@ void *BKE_simulation_add(Main *bmain, const char *name)
namespace blender::bke {
-static MutableSpan<float3> get_particle_positions(ParticleSimulationState *state)
-{
- return MutableSpan<float3>(
- (float3 *)CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position"),
- state->tot_particles);
-}
-
static void ensure_attributes_exist(ParticleSimulationState *state)
{
if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Position") == nullptr) {
CustomData_add_layer_named(
&state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Position");
}
+ if (CustomData_get_layer_named(&state->attributes, CD_LOCATION, "Velocity") == nullptr) {
+ CustomData_add_layer_named(
+ &state->attributes, CD_LOCATION, CD_CALLOC, nullptr, state->tot_particles, "Velocity");
+ }
}
-static void copy_particle_state_to_cow(ParticleSimulationState *state_orig,
- ParticleSimulationState *state_cow)
+static void copy_states_to_cow(Simulation *simulation_orig, Simulation *simulation_cow)
{
- ensure_attributes_exist(state_cow);
- CustomData_free(&state_cow->attributes, state_cow->tot_particles);
- CustomData_copy(&state_orig->attributes,
- &state_cow->attributes,
- CD_MASK_ALL,
- CD_DUPLICATE,
- state_orig->tot_particles);
- state_cow->current_frame = state_orig->current_frame;
- state_cow->tot_particles = state_orig->tot_particles;
+ LISTBASE_FOREACH_MUTABLE (SimulationState *, state_cow, &simulation_cow->states) {
+ switch ((eSimulationStateType)state_cow->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ BLI_remlink(&simulation_cow->states, state_cow);
+ free_particle_simulation_state((ParticleSimulationState *)state_cow);
+ break;
+ }
+ }
+ }
+ simulation_cow->current_frame = simulation_orig->current_frame;
+
+ LISTBASE_FOREACH (SimulationState *, state_orig, &simulation_orig->states) {
+ switch ((eSimulationStateType)state_orig->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ ParticleSimulationState *particle_state_orig = (ParticleSimulationState *)state_orig;
+ ParticleSimulationState *particle_state_cow = (ParticleSimulationState *)MEM_callocN(
+ sizeof(*particle_state_cow), AT);
+ particle_state_cow->tot_particles = particle_state_orig->tot_particles;
+ particle_state_cow->head.name = BLI_strdup(state_orig->name);
+ CustomData_copy(&particle_state_orig->attributes,
+ &particle_state_cow->attributes,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ particle_state_orig->tot_particles);
+ BLI_addtail(&simulation_cow->states, particle_state_cow);
+ break;
+ }
+ }
+ }
}
-static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation)
+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)
{
- int current_frame = scene->r.cfra;
+ Span<const DNode *> attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute");
+ uint amount = attribute_dnodes.size();
+ if (amount == 0) {
+ return {};
+ }
- ParticleSimulationState *state_cow = (ParticleSimulationState *)simulation->states.first;
- ParticleSimulationState *state_orig = (ParticleSimulationState *)state_cow->head.orig_state;
+ Vector<fn::MFInputSocket *> name_sockets;
+ for (const DNode *dnode : attribute_dnodes) {
+ fn::MFInputSocket &name_socket = network_map.lookup_dummy(dnode->input(0));
+ name_sockets.append(&name_socket);
+ }
- if (current_frame == state_cow->current_frame) {
- return;
+ fn::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()};
+
+ fn::MFParamsBuilder params{network_fn, 1};
+
+ Array<std::string> attribute_names{amount, NoInitialization()};
+ for (uint i : IndexRange(amount)) {
+ params.add_uninitialized_single_output(
+ fn::GMutableSpan(fn::CPPType_string, attribute_names.data() + i, 1));
+ }
+
+ fn::MFContextBuilder context;
+ /* Todo: Check that the names don't depend on dummy nodes. */
+ network_fn.call({0}, params, context);
+
+ Map<std::pair<std::string, fn::MFDataType>, Vector<fn::MFNode *>>
+ attribute_nodes_by_name_and_type;
+ for (uint i : IndexRange(amount)) {
+ attribute_nodes_by_name_and_type
+ .lookup_or_add_default({attribute_names[i], name_sockets[i]->data_type()})
+ .append(&name_sockets[i]->node());
}
- /* Number of particles should be stored in the cache, but for now assume it is constant. */
- state_cow->tot_particles = state_orig->tot_particles;
- CustomData_realloc(&state_cow->attributes, state_orig->tot_particles);
- ensure_attributes_exist(state_cow);
+ AttributeNodeMap final_attribute_nodes;
+ for (auto item : attribute_nodes_by_name_and_type.items()) {
+ StringRef attribute_name = item.key.first;
+ fn::MFDataType data_type = item.key.second;
+ Span<fn::MFNode *> nodes = item.value;
- PTCacheID pid_cow;
- BKE_ptcache_id_from_sim_particles(&pid_cow, state_cow);
- BKE_ptcache_id_time(&pid_cow, scene, current_frame, nullptr, nullptr, nullptr);
+ fn::MFOutputSocket &new_attribute_socket = network.add_input(
+ "Attribute '" + attribute_name + "'", data_type);
+ for (fn::MFNode *node : nodes) {
+ network.relink(node->output(0), new_attribute_socket);
+ }
+ network.remove(nodes);
+
+ final_attribute_nodes.add_new(&new_attribute_socket.node().as_dummy(), item.key);
+ }
+
+ return final_attribute_nodes;
+}
+
+class CustomDataAttributesRef {
+ private:
+ Vector<void *> buffers_;
+ uint size_;
+ std::unique_ptr<fn::AttributesInfo> info_;
+
+ public:
+ CustomDataAttributesRef(CustomData &custom_data, uint size)
+ {
+ 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});
+ }
+ info_ = std::make_unique<fn::AttributesInfo>(builder);
+ size_ = size;
+ }
+
+ operator fn::MutableAttributesRef()
+ {
+ return fn::MutableAttributesRef(*info_, buffers_, size_);
+ }
- /* If successfull, this will read the state directly into the cow state. */
- int cache_result = BKE_ptcache_read(&pid_cow, current_frame, true);
- if (cache_result == PTCACHE_READ_EXACT) {
- state_cow->current_frame = current_frame;
+ operator fn::AttributesRef() const
+ {
+ return fn::AttributesRef(*info_, buffers_, size_);
+ }
+};
+
+static std::string dnode_to_path(const DNode &dnode)
+{
+ std::string path;
+ for (const DParentNode *parent = dnode.parent(); parent; parent = parent->parent()) {
+ path = parent->node_ref().name() + "/" + path;
+ }
+ path = path + dnode.name();
+ return path;
+}
+
+static void remove_unused_states(Simulation *simulation, const VectorSet<std::string> &state_names)
+{
+ LISTBASE_FOREACH_MUTABLE (SimulationState *, state, &simulation->states) {
+ if (!state_names.contains(state->name)) {
+ BLI_remlink(&simulation->states, state);
+ free_particle_simulation_state((ParticleSimulationState *)state);
+ }
+ }
+}
+
+static void reset_states(Simulation *simulation)
+{
+ LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ switch ((eSimulationStateType)state->type) {
+ case SIM_STATE_TYPE_PARTICLES: {
+ ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
+ CustomData_free(&particle_state->attributes, particle_state->tot_particles);
+ particle_state->tot_particles = 0;
+ break;
+ }
+ }
+ }
+}
+
+static SimulationState *try_find_state_by_name(Simulation *simulation, StringRef name)
+{
+ LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
+ if (state->name == name) {
+ return state;
+ }
+ }
+ return nullptr;
+}
+
+static void add_missing_particle_states(Simulation *simulation, Span<std::string> state_names)
+{
+ for (StringRefNull name : state_names) {
+ SimulationState *state = try_find_state_by_name(simulation, name);
+ if (state != nullptr) {
+ BLI_assert(state->type == SIM_STATE_TYPE_PARTICLES);
+ continue;
+ }
+
+ ParticleSimulationState *particle_state = (ParticleSimulationState *)MEM_callocN(
+ sizeof(*particle_state), AT);
+ particle_state->head.type = SIM_STATE_TYPE_PARTICLES;
+ particle_state->head.name = BLI_strdup(name.data());
+ CustomData_reset(&particle_state->attributes);
+ particle_state->point_cache = BKE_ptcache_add(&particle_state->ptcaches);
+ BLI_addtail(&simulation->states, particle_state);
+ }
+}
+
+static void reinitialize_empty_simulation_states(Simulation *simulation,
+ const DerivedNodeTree &tree)
+{
+ VectorSet<std::string> state_names;
+ for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
+ state_names.add(dnode_to_path(*dnode));
+ }
+
+ remove_unused_states(simulation, state_names);
+ reset_states(simulation);
+ add_missing_particle_states(simulation, state_names);
+}
+
+static void update_simulation_state_list(Simulation *simulation, const DerivedNodeTree &tree)
+{
+ VectorSet<std::string> state_names;
+ for (const DNode *dnode : tree.nodes_by_type("SimulationNodeParticleSimulation")) {
+ state_names.add(dnode_to_path(*dnode));
+ }
+
+ remove_unused_states(simulation, state_names);
+ add_missing_particle_states(simulation, state_names);
+}
+
+static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulation *simulation_cow)
+{
+ int current_frame = scene->r.cfra;
+ if (simulation_cow->current_frame == current_frame) {
return;
}
@@ -227,34 +398,71 @@ static void simulation_data_update(Depsgraph *depsgraph, Scene *scene, Simulatio
return;
}
- PTCacheID pid_orig;
- BKE_ptcache_id_from_sim_particles(&pid_orig, state_orig);
- BKE_ptcache_id_time(&pid_orig, scene, current_frame, nullptr, nullptr, nullptr);
+ Simulation *simulation_orig = (Simulation *)DEG_get_original_id(&simulation_cow->id);
+
+ NodeTreeRefMap tree_refs;
+ /* TODO: Use simulation_cow, but need to add depsgraph relations before that. */
+ const DerivedNodeTree tree{simulation_orig->nodetree, tree_refs};
+ fn::MFNetwork network;
+ ResourceCollector resources;
+ MFNetworkTreeMap network_map = insert_node_tree_into_mf_network(network, tree, resources);
+ AttributeNodeMap attribute_node_map = deduplicate_attribute_nodes(network, network_map, tree);
+ fn::mf_network_optimization::constant_folding(network, resources);
+ fn::mf_network_optimization::common_subnetwork_elimination(network);
+ fn::mf_network_optimization::dead_node_removal(network);
+ UNUSED_VARS(attribute_node_map);
+ // WM_clipboard_text_set(network.to_dot().c_str(), false);
if (current_frame == 1) {
- state_orig->tot_particles = 100;
- state_orig->current_frame = 1;
- CustomData_realloc(&state_orig->attributes, state_orig->tot_particles);
- ensure_attributes_exist(state_orig);
-
- MutableSpan<float3> positions = get_particle_positions(state_orig);
- for (uint i : positions.index_range()) {
- positions[i] = {i / 10.0f, 0, 0};
+ reinitialize_empty_simulation_states(simulation_orig, tree);
+
+ RNG *rng = BLI_rng_new(0);
+
+ simulation_orig->current_frame = 1;
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) {
+ state->tot_particles = 100;
+ CustomData_realloc(&state->attributes, state->tot_particles);
+ ensure_attributes_exist(state);
+
+ CustomDataAttributesRef custom_data_attributes{state->attributes,
+ (uint)state->tot_particles};
+
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+ MutableSpan<float3> positions = attributes.get<float3>("Position");
+ MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
+
+ for (uint i : positions.index_range()) {
+ positions[i] = {i / 10.0f, 0, 0};
+ velocities[i] = {0, BLI_rng_get_float(rng), BLI_rng_get_float(rng) * 2 + 1};
+ }
}
- BKE_ptcache_write(&pid_orig, current_frame);
- copy_particle_state_to_cow(state_orig, state_cow);
+ BLI_rng_free(rng);
+
+ copy_states_to_cow(simulation_orig, simulation_cow);
}
- else if (current_frame == state_orig->current_frame + 1) {
- state_orig->current_frame = current_frame;
- ensure_attributes_exist(state_orig);
- MutableSpan<float3> positions = get_particle_positions(state_orig);
- for (float3 &position : positions) {
- position.z += 0.1f;
+ else if (current_frame == simulation_orig->current_frame + 1) {
+ update_simulation_state_list(simulation_orig, tree);
+ float time_step = 1.0f / 24.0f;
+ simulation_orig->current_frame = current_frame;
+
+ LISTBASE_FOREACH (ParticleSimulationState *, state, &simulation_orig->states) {
+ ensure_attributes_exist(state);
+
+ CustomDataAttributesRef custom_data_attributes{state->attributes,
+ (uint)state->tot_particles};
+
+ fn::MutableAttributesRef attributes = custom_data_attributes;
+ MutableSpan<float3> positions = attributes.get<float3>("Position");
+ MutableSpan<float3> velocities = attributes.get<float3>("Velocity");
+
+ for (uint i : positions.index_range()) {
+ velocities[i].z += -1.0f * time_step;
+ positions[i] += velocities[i] * time_step;
+ }
}
- BKE_ptcache_write(&pid_orig, current_frame);
- copy_particle_state_to_cow(state_orig, state_cow);
+ copy_states_to_cow(simulation_orig, simulation_cow);
}
}