Simulation output and input nodes

This commit is contained in:
Hans Goudey 2022-11-22 18:23:26 -06:00
parent 2cb6b0b4eb
commit 5aaa435ac7
12 changed files with 207 additions and 6 deletions

View File

@ -291,6 +291,17 @@ class NODE_MT_category_GEO_POINT(Menu):
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_simulation(Menu):
bl_idname = "NODE_MT_category_simulation"
bl_label = "Simulation"
def draw(self, _context):
layout = self.layout
node_add_menu.add_node_type(layout, "GeometryNodeSimulationInput")
node_add_menu.add_node_type(layout, "GeometryNodeSimulationOutput")
node_add_menu.draw_assets_for_catalog(layout, self.bl_label)
class NODE_MT_category_GEO_TEXT(Menu):
bl_idname = "NODE_MT_category_GEO_TEXT"
bl_label = "Text"
@ -428,6 +439,7 @@ class NODE_MT_geometry_node_add_all(Menu):
layout.menu("NODE_MT_geometry_node_mesh_topology")
layout.menu("NODE_MT_category_GEO_OUTPUT")
layout.menu("NODE_MT_category_GEO_POINT")
layout.menu("NODE_MT_category_simulation")
layout.menu("NODE_MT_category_GEO_TEXT")
layout.menu("NODE_MT_category_GEO_TEXTURE")
layout.menu("NODE_MT_category_GEO_UTILITIES")
@ -455,6 +467,7 @@ classes = (
NODE_MT_geometry_node_mesh_topology,
NODE_MT_category_GEO_OUTPUT,
NODE_MT_category_GEO_POINT,
NODE_MT_category_simulation,
NODE_MT_category_GEO_TEXT,
NODE_MT_category_GEO_TEXTURE,
NODE_MT_category_GEO_UTILITIES,

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_compute_context.hh"
#include "BLI_map.hh"
#include "BKE_geometry_set.hh"
namespace blender::bke {
struct CacheData {
Map<int, GeometrySet> geometry_per_frame;
};
struct ComputeCaches {
Map<ComputeContextHash, CacheData> cache_per_context;
};
} // namespace blender::bke

View File

@ -1396,6 +1396,9 @@ struct TexResult;
/** \name Geometry Nodes
* \{ */
#define GEO_NODE_SIMULATION_INPUT 1198
#define GEO_NODE_SIMULATION_OUTPUT 1199
#define GEO_NODE_TRIANGULATE 1000
#define GEO_NODE_TRANSFORM 1002
#define GEO_NODE_MESH_BOOLEAN 1003

View File

@ -2213,7 +2213,7 @@ bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idnam
BKE_ntree_update_tag_node_new(ntree, node);
if (ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) {
if (ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT, GEO_NODE_SIMULATION_INPUT)) {
DEG_relations_tag_update(CTX_data_main(C));
}
@ -3061,7 +3061,10 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
/* Also update relations for the scene time node, which causes a dependency
* on time that users expect to be removed when the node is removed. */
if (node_has_id || ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) {
if (node_has_id || ELEM(node->type,
GEO_NODE_INPUT_SCENE_TIME,
GEO_NODE_SELF_OBJECT,
GEO_NODE_SIMULATION_INPUT)) {
if (bmain != nullptr) {
DEG_relations_tag_update(bmain);
}
@ -4771,6 +4774,8 @@ static void registerGeometryNodes()
register_node_type_geo_set_shade_smooth();
register_node_type_geo_set_spline_cyclic();
register_node_type_geo_set_spline_resolution();
register_node_type_geo_simulation_input();
register_node_type_geo_simulation_output();
register_node_type_geo_store_named_attribute();
register_node_type_geo_string_join();
register_node_type_geo_string_to_curves();

View File

@ -10,6 +10,15 @@
#include "DNA_listBase.h"
#include "DNA_session_uuid_types.h"
#ifdef __cplusplus
namespace blender::bke {
struct ComputeCaches;
}
using ComputeCachesHandle = blender::bke::ComputeCaches;
#else
typedef struct ComputeCachesHandle ComputeCachesHandle;
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -2295,7 +2304,9 @@ typedef struct NodesModifierData {
* This can be used to help the user to debug a node tree.
*/
void *runtime_eval_log;
void *_pad1;
/** #ComputeCaches. */
ComputeCachesHandle *simulation_caches;
} NodesModifierData;
typedef struct MeshToVolumeModifierData {

View File

@ -37,6 +37,7 @@
#include "DNA_windowmanager_types.h"
#include "BKE_attribute_math.hh"
#include "BKE_compute_cache.hh"
#include "BKE_compute_contexts.hh"
#include "BKE_customdata.h"
#include "BKE_geometry_fields.hh"
@ -336,7 +337,7 @@ static bool check_tree_for_time_node(const bNodeTree &tree,
return false;
}
LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
if (ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SIMULATION_INPUT)) {
return true;
}
if (node->type == NODE_GROUP) {
@ -1106,6 +1107,7 @@ static GeometrySet compute_geometry(
const blender::nodes::GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
const bNode &output_node,
GeometrySet input_geometry_set,
blender::bke::ComputeCaches &compute_caches,
NodesModifierData *nmd,
const ModifierEvalContext *ctx)
{
@ -1133,6 +1135,7 @@ static GeometrySet compute_geometry(
blender::nodes::GeoNodesModifierData geo_nodes_modifier_data;
geo_nodes_modifier_data.depsgraph = ctx->depsgraph;
geo_nodes_modifier_data.self_object = ctx->object;
geo_nodes_modifier_data.cache_per_frame = &compute_caches;
auto eval_log = std::make_unique<GeoModifierLog>();
if (logging_enabled(ctx)) {
geo_nodes_modifier_data.eval_log = eval_log.get();
@ -1301,8 +1304,24 @@ static void modifyGeometry(ModifierData *md,
use_orig_index_polys = CustomData_has_layer(&mesh.pdata, CD_ORIGINDEX);
}
geometry_set = compute_geometry(
tree, *lf_graph_info, *output_node, std::move(geometry_set), nmd, ctx);
NodesModifierData *orig_nmd = reinterpret_cast<NodesModifierData *>(
BKE_modifier_get_original(ctx->object, md));
if (!orig_nmd->simulation_caches) {
orig_nmd->simulation_caches = new blender::bke::ComputeCaches();
}
geometry_set = compute_geometry(tree,
*lf_graph_info,
*output_node,
std::move(geometry_set),
*orig_nmd->simulation_caches,
nmd,
ctx);
if (orig_nmd->simulation_caches->cache_per_context.is_empty()) {
delete orig_nmd->simulation_caches;
orig_nmd->simulation_caches = nullptr;
}
if (geometry_set.has_mesh()) {
/* Add #CD_ORIGINDEX layers if they don't exist already. This is required because the
@ -1827,6 +1846,7 @@ static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const Modif
* and don't necessarily need to be written, but we can't just free them. */
IDP_BlendWrite(writer, nmd->settings.properties);
}
/* TODO: Write cached geometry. */
}
static void blendRead(BlendDataReader *reader, ModifierData *md)
@ -1840,6 +1860,8 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
IDP_BlendDataRead(reader, &nmd->settings.properties);
}
nmd->runtime_eval_log = nullptr;
/* TODO: Read cached geometry. */
nmd->simulation_caches = nullptr;
}
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
@ -1850,6 +1872,11 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
BKE_modifier_copydata_generic(md, target, flag);
tnmd->runtime_eval_log = nullptr;
if (nmd->simulation_caches) {
const blender::bke::ComputeCaches &src_caches = *static_cast<blender::bke::ComputeCaches *>(
nmd->simulation_caches);
tnmd->simulation_caches = new blender::bke::ComputeCaches(src_caches);
}
if (nmd->settings.properties != nullptr) {
tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag);
@ -1864,6 +1891,8 @@ static void freeData(ModifierData *md)
nmd->settings.properties = nullptr;
}
delete static_cast<blender::bke::ComputeCaches *>(nmd->simulation_caches);
clear_runtime_data(nmd);
}

View File

@ -151,6 +151,8 @@ void register_node_type_geo_set_position(void);
void register_node_type_geo_set_shade_smooth(void);
void register_node_type_geo_set_spline_cyclic(void);
void register_node_type_geo_set_spline_resolution(void);
void register_node_type_geo_simulation_input(void);
void register_node_type_geo_simulation_output(void);
void register_node_type_geo_store_named_attribute(void);
void register_node_type_geo_string_join(void);
void register_node_type_geo_string_to_curves(void);

View File

@ -26,6 +26,8 @@
#include "BLI_compute_context.hh"
#include "BKE_compute_cache.hh"
struct Object;
struct Depsgraph;
@ -44,6 +46,9 @@ struct GeoNodesModifierData {
Depsgraph *depsgraph = nullptr;
/** Optional logger. */
geo_eval_log::GeoModifierLog *eval_log = nullptr;
bke::ComputeCaches *cache_per_frame;
/**
* Some nodes should be executed even when their output is not used (e.g. active viewer nodes and
* the node groups they are contained in).

View File

@ -410,6 +410,8 @@ DefNode(GeometryNode, GEO_NODE_SET_POSITION, 0, "SET_POSITION", SetPosition, "Se
DefNode(GeometryNode, GEO_NODE_SET_SHADE_SMOOTH, 0, "SET_SHADE_SMOOTH", SetShadeSmooth, "Set Shade Smooth", "Control the smoothness of mesh normals around each face by changing the \"shade smooth\" attribute")
DefNode(GeometryNode, GEO_NODE_SET_SPLINE_CYCLIC, 0, "SET_SPLINE_CYCLIC", SetSplineCyclic, "Set Spline Cyclic", "Control whether each spline loops back on itself by changing the \"cyclic\" attribute")
DefNode(GeometryNode, GEO_NODE_SET_SPLINE_RESOLUTION, 0, "SET_SPLINE_RESOLUTION", SetSplineResolution, "Set Spline Resolution", "Control how many evaluated points should be generated on every curve segment")
DefNode(GeometryNode, GEO_NODE_SIMULATION_INPUT, 0, "SIMULATION_INPUT", SimulationInput, "Simulation Input", "")
DefNode(GeometryNode, GEO_NODE_SIMULATION_OUTPUT, 0, "SIMULATION_OUTPUT", SimulationOutput, "Simulation Output", "")
DefNode(GeometryNode, GEO_NODE_SPLIT_EDGES, 0, "SPLIT_EDGES", SplitEdges, "Split Edges", "Duplicate mesh edges and break connections with the surrounding faces")
DefNode(GeometryNode, GEO_NODE_STORE_NAMED_ATTRIBUTE, def_geo_store_named_attribute, "STORE_NAMED_ATTRIBUTE", StoreNamedAttribute, "Store Named Attribute", "Store the result of a field on a geometry as an attribute with the specified name")
DefNode(GeometryNode, GEO_NODE_STRING_JOIN, 0, "STRING_JOIN", StringJoin, "Join Strings", "Combine any number of input strings")

View File

@ -160,6 +160,8 @@ set(SRC
nodes/node_geo_set_shade_smooth.cc
nodes/node_geo_set_spline_cyclic.cc
nodes/node_geo_set_spline_resolution.cc
nodes/node_geo_simulation_input.cc
nodes/node_geo_simulation_output.cc
nodes/node_geo_store_named_attribute.cc
nodes/node_geo_string_join.cc
nodes/node_geo_string_to_curves.cc

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_simulation_input_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
static void node_geo_exec(GeoNodeExecParams params)
{
const Scene *scene = DEG_get_input_scene(params.depsgraph());
const float scene_ctime = BKE_scene_ctime_get(scene);
const int scene_frame = int(scene_ctime);
const int previous_frame = scene_frame - 1;
const GeoNodesLFUserData &lf_data = *params.user_data();
bke::ComputeCaches &all_caches = *lf_data.modifier_data->cache_per_frame;
bke::CacheData *cache = all_caches.cache_per_context.lookup_ptr(lf_data.compute_context->hash());
if (!cache) {
params.set_output("Geometry", params.extract_input<GeometrySet>("Geometry"));
return;
}
if (cache->geometry_per_frame.contains(previous_frame)) {
GeometrySet geometry_set = cache->geometry_per_frame.lookup(previous_frame);
params.set_output("Geometry", std::move(geometry_set));
// params.set_input_unused("Geometry");
return;
}
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes::node_geo_simulation_input_cc
void register_node_type_geo_simulation_input()
{
namespace file_ns = blender::nodes::node_geo_simulation_input_cc;
static bNodeType ntype;
geo_node_type_base(&ntype, GEO_NODE_SIMULATION_INPUT, "Simulation Input", NODE_CLASS_INTERFACE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}

View File

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_scene.h"
#include "DEG_depsgraph_query.h"
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_simulation_output_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Geometry>(N_("Geometry"));
b.add_output<decl::Geometry>(N_("Geometry"));
}
static void node_geo_exec(GeoNodeExecParams params)
{
const Scene *scene = DEG_get_input_scene(params.depsgraph());
const float scene_ctime = BKE_scene_ctime_get(scene);
const int scene_frame = int(scene_ctime);
const GeoNodesLFUserData &lf_data = *params.user_data();
bke::ComputeCaches &all_caches = *lf_data.modifier_data->cache_per_frame;
bke::CacheData &cache = all_caches.cache_per_context.lookup_or_add_default(
lf_data.compute_context->hash());
if (cache.geometry_per_frame.contains(scene_frame)) {
params.set_output("Geometry", cache.geometry_per_frame.lookup(scene_frame));
// params.set_input_unused("Geometry");
return;
}
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set.ensure_owns_direct_data();
cache.geometry_per_frame.add_new(scene_frame, geometry_set);
params.set_output("Geometry", std::move(geometry_set));
}
} // namespace blender::nodes::node_geo_simulation_output_cc
void register_node_type_geo_simulation_output()
{
namespace file_ns = blender::nodes::node_geo_simulation_output_cc;
static bNodeType ntype;
geo_node_type_base(
&ntype, GEO_NODE_SIMULATION_OUTPUT, "Simulation Output", NODE_CLASS_INTERFACE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
}