Add support for attributes storage in simulation state #107133

Merged
3 changed files with 316 additions and 24 deletions
Showing only changes of commit 9e58eba968 - Show all commits

View File

@ -13,21 +13,89 @@ class SimulationStateItem {
virtual ~SimulationStateItem() = default;
};
class GeometrySimulationStateItem : public SimulationStateItem {
template <typename T>
class TypedSimulationStateItem : public SimulationStateItem {
public:
using DataType = T;
private:
GeometrySet geometry_;
T data_;
public:
GeometrySimulationStateItem(GeometrySet geometry) : geometry_(std::move(geometry))
TypedSimulationStateItem() = default;
TypedSimulationStateItem(const T &data)
{
data_ = std::move(data);
}
TypedSimulationStateItem(T &&data)
{
data_ = std::move(data);
}
template <typename U>
TypedSimulationStateItem(const U &data)
{
data_ = data;
}
const GeometrySet &geometry() const
TypedSimulationStateItem(const TypedSimulationStateItem &) = delete;
TypedSimulationStateItem(TypedSimulationStateItem &&) = delete;
virtual ~TypedSimulationStateItem() {
}
TypedSimulationStateItem &operator=(const TypedSimulationStateItem &) = delete;
TypedSimulationStateItem &operator=(TypedSimulationStateItem &&) = delete;
const T &data() const
{
return geometry_;
return data_;
}
};
/** Specialization for GeometrySet which ensures the state owns the geometry data. */
template <>
class TypedSimulationStateItem<GeometrySet> : public SimulationStateItem {
public:
using DataType = GeometrySet;
private:
GeometrySet data_;
public:
TypedSimulationStateItem() = default;
TypedSimulationStateItem(const GeometrySet &data)
{
data_ = std::move(data);
data_.ensure_owns_direct_data();
}
TypedSimulationStateItem(GeometrySet &&data)
{
data_ = std::move(data);
data_.ensure_owns_direct_data();
}
template <typename U>
TypedSimulationStateItem(const U &data)
{
data_ = data;
data_.ensure_owns_direct_data();
}
TypedSimulationStateItem(const TypedSimulationStateItem &) = delete;
TypedSimulationStateItem(TypedSimulationStateItem &&) = delete;
virtual ~TypedSimulationStateItem() {
}
TypedSimulationStateItem &operator=(const TypedSimulationStateItem &) = delete;
TypedSimulationStateItem &operator=(TypedSimulationStateItem &&) = delete;
const GeometrySet &data() const
{
return data_;
}
};
class SimulationZoneState {
public:
Vector<std::unique_ptr<SimulationStateItem>> items;

View File

@ -12,6 +12,128 @@
#include "node_geometry_util.hh"
namespace blender::nodes {
template <typename T>
static void copy_typed_initial_simulation_state(lf::Params &params, int index)
{
T *data = params.try_get_input_data_ptr_or_request<T>(index);
if (data != nullptr) {
params.set_output(index + 1, std::move(*data));
}
}
static void copy_initial_simulation_state(
lf::Params &params,
int index,
short socket_type)
{
switch (socket_type) {
case SOCK_FLOAT:
LukasTonne marked this conversation as resolved
Review

Maybe I'm being stupid, but I don't get what's meant by "next" here.

Maybe I'm being stupid, but I don't get what's meant by "next" here.
Review

Was just an ad-hoc name: it's copying from the simulation state into the output parameter for the next iteration. I'll add some comments.

Was just an ad-hoc name: it's copying from the simulation state into the output parameter for the next iteration. I'll add some comments.
Review

Renamed the functions and added comments for clarity. Also the copy_simulation_state_to_output_param function is now shared by input and output node, they both need to do this: input node when preparing the next iteration, output node when outputting the sim result.

Renamed the functions and added comments for clarity. Also the `copy_simulation_state_to_output_param` function is now shared by input and output node, they both need to do this: input node when preparing the next iteration, output node when outputting the sim result.
copy_typed_initial_simulation_state<ValueOrField<float>>(params, index);
break;
case SOCK_VECTOR:
copy_typed_initial_simulation_state<ValueOrField<float3>>(params, index);
break;
case SOCK_RGBA:
copy_typed_initial_simulation_state<ValueOrField<ColorGeometry4f>>(params, index);
break;
case SOCK_BOOLEAN:
copy_typed_initial_simulation_state<ValueOrField<bool>>(params, index);
break;
case SOCK_INT:
copy_typed_initial_simulation_state<ValueOrField<int>>(params, index);
break;
case SOCK_STRING:
copy_typed_initial_simulation_state<ValueOrField<std::string>>(params, index);
break;
case SOCK_OBJECT:
copy_typed_initial_simulation_state<Object *>(params, index);
break;
case SOCK_GEOMETRY:
copy_typed_initial_simulation_state<GeometrySet>(params, index);
break;
case SOCK_COLLECTION:
copy_typed_initial_simulation_state<Collection *>(params, index);
break;
case SOCK_TEXTURE:
copy_typed_initial_simulation_state<Tex *>(params, index);
break;
case SOCK_IMAGE:
copy_typed_initial_simulation_state<Image *>(params, index);
break;
case SOCK_MATERIAL:
copy_typed_initial_simulation_state<Material *>(params, index);
break;
default:
BLI_assert_unreachable();
copy_typed_initial_simulation_state<GeometrySet>(params, index);
break;
}
}
template<typename T>
static void copy_typed_next_simulation_state(lf::Params &params,
int index,
const bke::sim::SimulationStateItem &state_item)
{
if (auto *typed_state_item = dynamic_cast<const bke::sim::TypedSimulationStateItem<T> *>(
&state_item)) {
params.set_output(index + 1, typed_state_item->data());
}
}
static void copy_next_simulation_state(lf::Params &params,
int index,
short socket_type,
const bke::sim::SimulationStateItem &state_item)
{
switch (socket_type) {
case SOCK_FLOAT:
copy_typed_next_simulation_state<ValueOrField<float>>(params, index, state_item);
break;
case SOCK_VECTOR:
copy_typed_next_simulation_state<ValueOrField<float3>>(params, index, state_item);
break;
case SOCK_RGBA:
copy_typed_next_simulation_state<ValueOrField<ColorGeometry4f>>(params, index, state_item);
break;
case SOCK_BOOLEAN:
copy_typed_next_simulation_state<ValueOrField<bool>>(params, index, state_item);
break;
case SOCK_INT:
copy_typed_next_simulation_state<ValueOrField<int>>(params, index, state_item);
break;
case SOCK_STRING:
copy_typed_next_simulation_state<ValueOrField<std::string>>(params, index, state_item);
break;
case SOCK_OBJECT:
copy_typed_next_simulation_state<Object *>(params, index, state_item);
break;
case SOCK_GEOMETRY:
copy_typed_next_simulation_state<GeometrySet>(params, index, state_item);
break;
case SOCK_COLLECTION:
copy_typed_next_simulation_state<Collection *>(params, index, state_item);
break;
case SOCK_TEXTURE:
copy_typed_next_simulation_state<Tex *>(params, index, state_item);
break;
case SOCK_IMAGE:
copy_typed_next_simulation_state<Image *>(params, index, state_item);
break;
case SOCK_MATERIAL:
copy_typed_next_simulation_state<Material *>(params, index, state_item);
break;
default:
BLI_assert_unreachable();
copy_typed_next_simulation_state<GeometrySet>(params, index, state_item);
break;
}
}
}
namespace blender::nodes::node_geo_simulation_input_cc {
NODE_STORAGE_FUNCS(NodeGeometrySimulationInput);
@ -63,10 +185,7 @@ class LazyFunctionForSimulationInputNode final : public LazyFunction {
if (params.output_was_set(i + 1)) {
continue;
}
GeometrySet *geometry = params.try_get_input_data_ptr_or_request<GeometrySet>(i);
if (geometry != nullptr) {
params.set_output(i + 1, std::move(*geometry));
}
copy_initial_simulation_state(params, i, simulation_items_[i].socket_type);
}
}
else {
@ -75,10 +194,9 @@ class LazyFunctionForSimulationInputNode final : public LazyFunction {
params.set_output(i + 1, GeometrySet());
continue;
}
const bke::sim::SimulationStateItem *item = prev_zone_state->items[i].get();
if (auto *geometry_item = dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(
item)) {
params.set_output(i + 1, geometry_item->geometry());
const bke::sim::SimulationStateItem *state_item = prev_zone_state->items[i].get();
if (state_item != nullptr) {
copy_next_simulation_state(params, i, simulation_items_[i].socket_type, *state_item);
}
}
}

View File

@ -155,6 +155,112 @@ const CPPType &get_simulation_item_cpp_type(const NodeSimulationItem &item)
}
}
template <typename T>
static std::unique_ptr<bke::sim::TypedSimulationStateItem<T>> make_typed_simulation_state_item(lf::Params &params, int index)
{
using bke::sim::TypedSimulationStateItem;
if (const T *data = params.try_get_input_data_ptr_or_request<T>(index)) {
return std::make_unique<TypedSimulationStateItem<T>>(*data);
}
return std::make_unique<TypedSimulationStateItem<T>>();
}
static std::unique_ptr<bke::sim::SimulationStateItem> make_simulation_state_item(
lf::Params &params, int index, short socket_type)
{
switch (socket_type) {
case SOCK_FLOAT:
return make_typed_simulation_state_item<ValueOrField<float>>(params, index);
case SOCK_VECTOR:
return make_typed_simulation_state_item<ValueOrField<float3>>(params, index);
case SOCK_RGBA:
return make_typed_simulation_state_item<ValueOrField<ColorGeometry4f>>(params, index);
case SOCK_BOOLEAN:
return make_typed_simulation_state_item<ValueOrField<bool>>(params, index);
case SOCK_INT:
return make_typed_simulation_state_item<ValueOrField<int>>(params, index);
case SOCK_STRING:
return make_typed_simulation_state_item<ValueOrField<std::string>>(params, index);
case SOCK_OBJECT:
return make_typed_simulation_state_item<Object *>(params, index);
case SOCK_GEOMETRY:
return make_typed_simulation_state_item<GeometrySet>(params, index);
case SOCK_COLLECTION:
return make_typed_simulation_state_item<Collection *>(params, index);
case SOCK_TEXTURE:
return make_typed_simulation_state_item<Tex *>(params, index);
case SOCK_IMAGE:
return make_typed_simulation_state_item<Image *>(params, index);
case SOCK_MATERIAL:
return make_typed_simulation_state_item<Material *>(params, index);
default:
BLI_assert_unreachable();
return make_typed_simulation_state_item<GeometrySet>(params, index);
}
}
template <typename T>
static void copy_typed_simulation_state_output(lf::Params &params, int index, const bke::sim::SimulationStateItem &state_item)
{
using bke::sim::TypedSimulationStateItem;
if (auto *typed_state_item = dynamic_cast<const bke::sim::TypedSimulationStateItem<T> *>(&state_item)) {
params.set_output(index, typed_state_item->data());
}
}
static void copy_simulation_state_output(
lf::Params &params,
int index,
short socket_type,
const bke::sim::SimulationStateItem &state_item)
{
switch (socket_type) {
case SOCK_FLOAT:
copy_typed_simulation_state_output<ValueOrField<float>>(params, index, state_item);
break;
case SOCK_VECTOR:
copy_typed_simulation_state_output<ValueOrField<float3>>(params, index, state_item);
break;
case SOCK_RGBA:
copy_typed_simulation_state_output<ValueOrField<ColorGeometry4f>>(params, index, state_item);
break;
case SOCK_BOOLEAN:
copy_typed_simulation_state_output<ValueOrField<bool>>(params, index, state_item);
break;
case SOCK_INT:
copy_typed_simulation_state_output<ValueOrField<int>>(params, index, state_item);
break;
case SOCK_STRING:
copy_typed_simulation_state_output<ValueOrField<std::string>>(params, index, state_item);
break;
case SOCK_OBJECT:
copy_typed_simulation_state_output<Object *>(params, index, state_item);
break;
case SOCK_GEOMETRY:
copy_typed_simulation_state_output<GeometrySet>(params, index, state_item);
break;
case SOCK_COLLECTION:
copy_typed_simulation_state_output<Collection *>(params, index, state_item);
break;
case SOCK_TEXTURE:
copy_typed_simulation_state_output<Tex *>(params, index, state_item);
break;
case SOCK_IMAGE:
copy_typed_simulation_state_output<Image *>(params, index, state_item);
break;
case SOCK_MATERIAL:
copy_typed_simulation_state_output<Material *>(params, index, state_item);
break;
default:
BLI_assert_unreachable();
copy_typed_simulation_state_output<GeometrySet>(params, index, state_item);
break;
}
}
} // namespace blender::nodes
namespace blender::nodes::node_geo_simulation_output_cc {
@ -224,14 +330,15 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
bool all_available = true;
for (const int i : simulation_items_.index_range()) {
GeometrySet *input_geometry = params.try_get_input_data_ptr_or_request<GeometrySet>(i);
if (input_geometry == nullptr) {
const NodeSimulationItem &item = simulation_items_[i];
void *input_data = params.try_get_input_data_ptr_or_request(i);
if (input_data == nullptr) {
all_available = false;
continue;
}
input_geometry->ensure_owns_direct_data();
new_zone_state.items[i] = std::make_unique<bke::sim::GeometrySimulationStateItem>(
std::move(*input_geometry));
new_zone_state.items[i] = make_simulation_state_item(params, i, item.socket_type);
}
if (all_available) {
@ -242,17 +349,16 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
void output_cached_state(lf::Params &params, const bke::sim::SimulationZoneState &state) const
{
for (const int i : simulation_items_.index_range()) {
const NodeSimulationItem &item = simulation_items_[i];
if (i >= state.items.size()) {
continue;
}
const bke::sim::SimulationStateItem *item = state.items[i].get();
if (item == nullptr) {
const bke::sim::SimulationStateItem *state_item = state.items[i].get();
if (state_item == nullptr) {
continue;
}
if (auto *geometry_item = dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(
item)) {
params.set_output(i, geometry_item->geometry());
}
copy_simulation_state_output(params, i, item.socket_type, *state_item);
}
params.set_default_remaining_outputs();
}