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.
This commit is contained in:
@@ -296,7 +296,9 @@ void BKE_ptcache_id_from_dynamicpaint(PTCacheID *pid,
|
||||
struct Object *ob,
|
||||
struct DynamicPaintSurface *surface);
|
||||
void BKE_ptcache_id_from_rigidbody(PTCacheID *pid, struct Object *ob, struct RigidBodyWorld *rbw);
|
||||
void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, struct ParticleSimulationState *state);
|
||||
void BKE_ptcache_id_from_sim_particles(PTCacheID *pid,
|
||||
struct ParticleSimulationState *state_orig,
|
||||
struct ParticleSimulationState *state_cow);
|
||||
|
||||
PTCacheID BKE_ptcache_id_find(struct Object *ob, struct Scene *scene, struct PointCache *cache);
|
||||
void BKE_ptcache_ids_from_object(struct ListBase *lb,
|
||||
|
||||
@@ -1772,7 +1772,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
|
||||
/* 42: CD_SCULPT_FACE_SETS */
|
||||
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
/* 43: CD_LOCATION */
|
||||
{sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
{sizeof(float[3]), "vec3f", 1, "Location", NULL, NULL, NULL, NULL, NULL},
|
||||
/* 44: CD_RADIUS */
|
||||
{sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
/* 45: CD_HAIRCURVE */
|
||||
|
||||
@@ -1898,19 +1898,13 @@ static void ptcache_sim_particle_read(
|
||||
PTCACHE_DATA_TO(data, BPHYS_DATA_LOCATION, 0, positions + (index * 3));
|
||||
}
|
||||
|
||||
void BKE_ptcache_id_from_sim_particles(PTCacheID *pid, ParticleSimulationState *state)
|
||||
void BKE_ptcache_id_from_sim_particles(PTCacheID *pid,
|
||||
ParticleSimulationState *state_orig,
|
||||
ParticleSimulationState *state_cow)
|
||||
{
|
||||
memset(pid, 0, sizeof(PTCacheID));
|
||||
|
||||
ParticleSimulationState *state_orig;
|
||||
if (state->head.orig_state != NULL) {
|
||||
state_orig = (ParticleSimulationState *)state->head.orig_state;
|
||||
}
|
||||
else {
|
||||
state_orig = state;
|
||||
}
|
||||
|
||||
pid->calldata = state;
|
||||
pid->calldata = state_cow;
|
||||
pid->type = PTCACHE_TYPE_SIM_PARTICLES;
|
||||
pid->cache = state_orig->point_cache;
|
||||
pid->cache_ptr = &state_orig->point_cache;
|
||||
@@ -2050,11 +2044,7 @@ static bool foreach_object_modifier_ptcache(Object *object,
|
||||
LISTBASE_FOREACH (SimulationState *, state, &smd->simulation->states) {
|
||||
switch ((eSimulationStateType)state->type) {
|
||||
case SIM_STATE_TYPE_PARTICLES: {
|
||||
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
|
||||
BKE_ptcache_id_from_sim_particles(&pid, particle_state);
|
||||
if (!callback(&pid, callback_user_data)) {
|
||||
return false;
|
||||
}
|
||||
/* TODO(jacques) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
ParticleSimulationState *state_cow = (ParticleSimulationState *)simulation->states.first;
|
||||
ParticleSimulationState *state_orig = (ParticleSimulationState *)state_cow->head.orig_state;
|
||||
|
||||
if (current_frame == state_cow->current_frame) {
|
||||
return;
|
||||
Span<const DNode *> attribute_dnodes = tree.nodes_by_type("SimulationNodeParticleAttribute");
|
||||
uint amount = attribute_dnodes.size();
|
||||
if (amount == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
}
|
||||
|
||||
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::MFNetworkEvaluator network_fn{{}, name_sockets.as_span()};
|
||||
|
||||
/* 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;
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
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);
|
||||
reinitialize_empty_simulation_states(simulation_orig, tree);
|
||||
|
||||
MutableSpan<float3> positions = get_particle_positions(state_orig);
|
||||
for (uint i : positions.index_range()) {
|
||||
positions[i] = {i / 10.0f, 0, 0};
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8686,6 +8686,7 @@ static void direct_link_simulation(BlendDataReader *reader, Simulation *simulati
|
||||
|
||||
BLO_read_list(reader, &simulation->states);
|
||||
LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
|
||||
BLO_read_data_address(reader, &state->name);
|
||||
switch ((eSimulationStateType)state->type) {
|
||||
case SIM_STATE_TYPE_PARTICLES: {
|
||||
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
|
||||
|
||||
@@ -3832,6 +3832,7 @@ static void write_simulation(BlendWriter *writer, Simulation *simulation, const
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (SimulationState *, state, &simulation->states) {
|
||||
BLO_write_string(writer, state->name);
|
||||
switch ((eSimulationStateType)state->type) {
|
||||
case SIM_STATE_TYPE_PARTICLES: {
|
||||
ParticleSimulationState *particle_state = (ParticleSimulationState *)state;
|
||||
|
||||
@@ -711,13 +711,6 @@ void update_modifiers_orig_pointers(const Object *object_orig, Object *object_co
|
||||
&object_orig->modifiers, &object_cow->modifiers, &ModifierData::orig_modifier_data);
|
||||
}
|
||||
|
||||
void update_simulation_states_orig_pointers(const Simulation *simulation_orig,
|
||||
Simulation *simulation_cow)
|
||||
{
|
||||
update_list_orig_pointers(
|
||||
&simulation_orig->states, &simulation_cow->states, &SimulationState::orig_state);
|
||||
}
|
||||
|
||||
void update_nla_strips_orig_pointers(const ListBase *strips_orig, ListBase *strips_cow)
|
||||
{
|
||||
NlaStrip *strip_orig = reinterpret_cast<NlaStrip *>(strips_orig->first);
|
||||
@@ -817,12 +810,6 @@ void update_id_after_copy(const Depsgraph *depsgraph,
|
||||
update_scene_orig_pointers(scene_orig, scene_cow);
|
||||
break;
|
||||
}
|
||||
case ID_SIM: {
|
||||
Simulation *simulation_cow = (Simulation *)id_cow;
|
||||
const Simulation *simulation_orig = (const Simulation *)id_orig;
|
||||
update_simulation_states_orig_pointers(simulation_orig, simulation_cow);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2146,7 +2146,7 @@ typedef struct SimulationModifierData {
|
||||
ModifierData modifier;
|
||||
|
||||
struct Simulation *simulation;
|
||||
char data_path[64];
|
||||
char *data_path;
|
||||
} SimulationModifierData;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef struct Simulation {
|
||||
struct bNodeTree *nodetree;
|
||||
|
||||
int flag;
|
||||
int _pad;
|
||||
float current_frame;
|
||||
|
||||
/** List containing SimulationState objects. */
|
||||
struct ListBase states;
|
||||
@@ -41,23 +41,19 @@ typedef struct SimulationState {
|
||||
struct SimulationState *next;
|
||||
struct SimulationState *prev;
|
||||
|
||||
/** This is only initialized on cow copies of the simulation. It points to the state on the
|
||||
* original data block. That is where the cache is stored. */
|
||||
struct SimulationState *orig_state;
|
||||
|
||||
/** eSimulationStateType */
|
||||
int type;
|
||||
int _pad;
|
||||
|
||||
char name[64];
|
||||
char *name;
|
||||
} SimulationState;
|
||||
|
||||
typedef struct ParticleSimulationState {
|
||||
SimulationState head;
|
||||
|
||||
/** Contains the state of the particles at time current_frame. */
|
||||
float current_frame;
|
||||
/** Contains the state of the particles at time Simulation->current_frame. */
|
||||
int tot_particles;
|
||||
int _pad;
|
||||
struct CustomData attributes;
|
||||
|
||||
/** Caches the state of the particles over time. The cache only exists on the original data
|
||||
|
||||
@@ -1639,6 +1639,40 @@ static void rna_SimulationModifier_simulation_update(Main *bmain, Scene *scene,
|
||||
rna_Modifier_dependency_update(bmain, scene, ptr);
|
||||
}
|
||||
|
||||
static void rna_SimulationModifier_data_path_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
SimulationModifierData *smd = ptr->data;
|
||||
|
||||
if (smd->data_path) {
|
||||
strcpy(value, smd->data_path);
|
||||
}
|
||||
else {
|
||||
value[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_SimulationModifier_data_path_length(PointerRNA *ptr)
|
||||
{
|
||||
SimulationModifierData *smd = ptr->data;
|
||||
return smd->data_path ? strlen(smd->data_path) : 0;
|
||||
}
|
||||
|
||||
static void rna_SimulationModifier_data_path_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
SimulationModifierData *smd = ptr->data;
|
||||
|
||||
if (smd->data_path) {
|
||||
MEM_freeN(smd->data_path);
|
||||
}
|
||||
|
||||
if (value[0]) {
|
||||
smd->data_path = BLI_strdup(value);
|
||||
}
|
||||
else {
|
||||
smd->data_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special set callback that just changes the first bit of the expansion flag.
|
||||
* This way the expansion state of all the sub-panels is not changed by RNA.
|
||||
@@ -6859,6 +6893,10 @@ static void rna_def_modifier_simulation(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, 0, "rna_SimulationModifier_simulation_update");
|
||||
|
||||
prop = RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_funcs(prop,
|
||||
"rna_SimulationModifier_data_path_get",
|
||||
"rna_SimulationModifier_data_path_length",
|
||||
"rna_SimulationModifier_data_path_set");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Data Path", "Identifier of the simulation component that should be accessed");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
@@ -47,6 +48,8 @@
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_simulation.h"
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
/* SpaceType struct has a member called 'new' which obviously conflicts with C++
|
||||
* so temporarily redefining the new keyword to make it compile. */
|
||||
#define new extern_new
|
||||
@@ -93,9 +96,14 @@ static const ParticleSimulationState *find_particle_state(SimulationModifierData
|
||||
if (smd->simulation == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (smd->data_path == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
LISTBASE_FOREACH (const SimulationState *, state, &smd->simulation->states) {
|
||||
if (state->type == SIM_STATE_TYPE_PARTICLES) {
|
||||
return (ParticleSimulationState *)state;
|
||||
if (STREQ(smd->data_path, state->name)) {
|
||||
if (state->type == SIM_STATE_TYPE_PARTICLES) {
|
||||
return (ParticleSimulationState *)state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -121,7 +129,7 @@ static PointCloud *modifyPointCloud(ModifierData *md,
|
||||
memcpy(pointcloud->co, positions, sizeof(float3) * state->tot_particles);
|
||||
|
||||
for (int i = 0; i < state->tot_particles; i++) {
|
||||
pointcloud->radius[i] = 0.05f;
|
||||
pointcloud->radius[i] = 0.1f;
|
||||
}
|
||||
|
||||
return pointcloud;
|
||||
@@ -146,6 +154,37 @@ static void panelRegister(ARegionType *region_type)
|
||||
modifier_panel_register(region_type, eModifierType_Simulation, panel_draw);
|
||||
}
|
||||
|
||||
static void blendWrite(BlendWriter *writer, const ModifierData *md)
|
||||
{
|
||||
const SimulationModifierData *smd = (const SimulationModifierData *)md;
|
||||
BLO_write_string(writer, smd->data_path);
|
||||
}
|
||||
|
||||
static void blendRead(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
SimulationModifierData *smd = (SimulationModifierData *)md;
|
||||
BLO_read_data_address(reader, &smd->data_path);
|
||||
}
|
||||
|
||||
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
|
||||
{
|
||||
const SimulationModifierData *smd = (const SimulationModifierData *)md;
|
||||
SimulationModifierData *tsmd = (SimulationModifierData *)target;
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flag);
|
||||
if (smd->data_path != nullptr) {
|
||||
tsmd->data_path = BLI_strdup(smd->data_path);
|
||||
}
|
||||
}
|
||||
|
||||
static void freeData(ModifierData *md)
|
||||
{
|
||||
SimulationModifierData *smd = (SimulationModifierData *)md;
|
||||
if (smd->data_path) {
|
||||
MEM_freeN(smd->data_path);
|
||||
}
|
||||
}
|
||||
|
||||
ModifierTypeInfo modifierType_Simulation = {
|
||||
/* name */ "Simulation",
|
||||
/* structName */ "SimulationModifierData",
|
||||
@@ -153,7 +192,7 @@ ModifierTypeInfo modifierType_Simulation = {
|
||||
/* type */ eModifierTypeType_None,
|
||||
/* flags */ (ModifierTypeFlag)0,
|
||||
|
||||
/* copyData */ BKE_modifier_copydata_generic,
|
||||
/* copyData */ copyData,
|
||||
|
||||
/* deformVerts */ NULL,
|
||||
/* deformMatrices */ NULL,
|
||||
@@ -166,7 +205,7 @@ ModifierTypeInfo modifierType_Simulation = {
|
||||
|
||||
/* initData */ NULL,
|
||||
/* requiredDataMask */ NULL,
|
||||
/* freeData */ NULL,
|
||||
/* freeData */ freeData,
|
||||
/* isDisabled */ isDisabled,
|
||||
/* updateDepsgraph */ updateDepsgraph,
|
||||
/* dependsOnTime */ NULL,
|
||||
@@ -176,6 +215,6 @@ ModifierTypeInfo modifierType_Simulation = {
|
||||
/* foreachTexLink */ NULL,
|
||||
/* freeRuntimeData */ NULL,
|
||||
/* panelRegister */ panelRegister,
|
||||
/* blendWrite */ NULL,
|
||||
/* blendRead */ NULL,
|
||||
/* blendWrite */ blendWrite,
|
||||
/* blendRead */ blendRead,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user