Geometry Nodes: add simulation support #104924
|
@ -17,6 +17,7 @@ struct GeometryCacheValue {
|
|||
GeometrySet geometry_set;
|
||||
};
|
||||
|
||||
/* TODO: Clear cache when editing nodes? Only sometimes, when persistent caching is turned off. */
|
||||
struct SimulationCache {
|
||||
Vector<GeometryCacheValue> geometry_per_frame;
|
||||
|
||||
|
@ -29,6 +30,15 @@ struct SimulationCache {
|
|||
return &geometry_per_frame[index];
|
||||
}
|
||||
|
||||
GeometryCacheValue *value_at_or_before_time(const int frame)
|
||||
{
|
||||
const int index = this->index_at_or_before_time(frame);
|
||||
if (index >= geometry_per_frame.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &geometry_per_frame[index];
|
||||
}
|
||||
|
||||
const GeometryCacheValue *value_before_time(const int frame) const
|
||||
{
|
||||
const int index = this->index_before_time(frame);
|
||||
|
@ -80,7 +90,7 @@ struct SimulationCache {
|
|||
}
|
||||
int insert_index = 0;
|
||||
for (const int i : geometry_per_frame.index_range()) {
|
||||
if (geometry_per_frame[i].frame >= frame) {
|
||||
if (geometry_per_frame[i].frame <= frame) {
|
||||
break;
|
||||
}
|
||||
insert_index++;
|
||||
|
@ -94,7 +104,7 @@ struct SimulationCache {
|
|||
}
|
||||
int insert_index = 0;
|
||||
for (const int i : geometry_per_frame.index_range()) {
|
||||
if (geometry_per_frame[i].frame > frame) {
|
||||
if (geometry_per_frame[i].frame < frame) {
|
||||
break;
|
||||
}
|
||||
insert_index++;
|
||||
|
@ -121,6 +131,10 @@ struct ComputeCaches {
|
|||
return cache_per_context.lookup_ptr(context_hash);
|
||||
}
|
||||
|
||||
/* TODO: Do we need to use the same context for multiple simulation inputs and outputs in the
|
||||
* same node group? If so this won't work at all-- we would need some way to link the two nodes,
|
||||
* which might be necessary for the "Run" socket anyway, since it needs to know whether the
|
||||
* simulation is running in order to know whether to use the last cache or request a new one. */
|
||||
SimulationCache &ensure_for_context(const ComputeContextHash &context_hash)
|
||||
{
|
||||
std::scoped_lock lock{mutex};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_compute_cache.hh"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
@ -34,7 +35,8 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
const float scene_ctime = BKE_scene_ctime_get(scene);
|
||||
const int scene_frame = int(scene_ctime);
|
||||
|
||||
/* TODO: Somehow use "Run" input. */
|
||||
/* TODO: Somehow use "Run" input. We also need to pass through the simulation state directly to
|
||||
* the output node on the first frame the "Run" input is true. */
|
||||
|
||||
const GeoNodesLFUserData &lf_data = *params.user_data();
|
||||
bke::ComputeCaches &all_caches = *lf_data.modifier_data->cache_per_frame;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BKE_compute_cache.hh"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
@ -94,15 +95,19 @@ static void node_geo_exec(GeoNodeExecParams params)
|
|||
|
||||
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
if (storage.use_cache) {
|
||||
/* TODO: The "Use cache" input should probably become a "Persistent Cache" option. */
|
||||
if (storage.use_cache || cache.geometry_per_frame.is_empty()) {
|
||||
/* If using the cache or there is no cached data yet, write the input in a new cache value. */
|
||||
cache.insert(geometry_set, scene_frame, scene_ctime);
|
||||
}
|
||||
else {
|
||||
bke::GeometryCacheValue &data = cache.value_at_time_ensure(scene_frame);
|
||||
data.frame = scene_frame;
|
||||
data.geometry_set = geometry_set;
|
||||
/* If we aren't using the cache, overrite the cache to only store the last frame. */
|
||||
/* TODO: This breaks the elapsed time. */
|
||||
data.time = scene_ctime;
|
||||
/* TODO: Should we allow turning on and off caching procedurally? In that case we wouldn't be
|
||||
* able to clear the whole cache, we would have to check if persistent caching was enabled for
|
||||
* the *last* frame and then decide to replace it or not. */
|
||||
cache.geometry_per_frame.clear();
|
||||
cache.insert(geometry_set, scene_frame, scene_ctime);
|
||||
}
|
||||
|
||||
params.set_output("Geometry", std::move(geometry_set));
|
||||
|
|
Loading…
Reference in New Issue