Geometry Nodes: add simulation support #104924
|
@ -246,7 +246,7 @@ class NewGeometryNodeTreeAssign(Operator):
|
|||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SimulationZoneOperator():
|
||||
class SimulationZoneOperator:
|
||||
input_node_type = 'GeometryNodeSimulationInput'
|
||||
output_node_type = 'GeometryNodeSimulationOutput'
|
||||
|
||||
|
@ -273,7 +273,7 @@ class SimulationZoneOperator():
|
|||
|
||||
|
||||
class SimulationZoneItemAddOperator(SimulationZoneOperator, Operator):
|
||||
'''Add a state item to the simulation zone'''
|
||||
"""Add a state item to the simulation zone"""
|
||||
bl_idname = "node.simulation_zone_item_add"
|
||||
bl_label = "Add State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -295,7 +295,7 @@ class SimulationZoneItemAddOperator(SimulationZoneOperator, Operator):
|
|||
|
||||
|
||||
class SimulationZoneItemRemoveOperator(SimulationZoneOperator, Operator):
|
||||
'''Remove a state item from the simulation zone'''
|
||||
"""Remove a state item from the simulation zone"""
|
||||
bl_idname = "node.simulation_zone_item_remove"
|
||||
bl_label = "Remove State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
@ -312,7 +312,7 @@ class SimulationZoneItemRemoveOperator(SimulationZoneOperator, Operator):
|
|||
|
||||
|
||||
class SimulationZoneItemMoveOperator(SimulationZoneOperator, Operator):
|
||||
'''Move a simulation state item up or down in the list'''
|
||||
"""Move a simulation state item up or down in the list"""
|
||||
bl_idname = "node.simulation_zone_item_move"
|
||||
bl_label = "Move State Item"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
|
|
@ -1426,9 +1426,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
/** \name Geometry Nodes
|
||||
* \{ */
|
||||
|
||||
#define GEO_NODE_SIMULATION_INPUT 2100
|
||||
#define GEO_NODE_SIMULATION_OUTPUT 2101
|
||||
|
||||
#define GEO_NODE_TRIANGULATE 1000
|
||||
#define GEO_NODE_TRANSFORM_GEOMETRY 1002
|
||||
#define GEO_NODE_MESH_BOOLEAN 1003
|
||||
|
@ -1587,6 +1584,9 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
|||
#define GEO_NODE_MEAN_FILTER_SDF_VOLUME 1197
|
||||
#define GEO_NODE_OFFSET_SDF_VOLUME 1198
|
||||
#define GEO_NODE_INDEX_OF_NEAREST 1199
|
||||
/* Function nodes use the range starting at 1200. */
|
||||
#define GEO_NODE_SIMULATION_INPUT 2100
|
||||
#define GEO_NODE_SIMULATION_OUTPUT 2101
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -4331,7 +4331,9 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
do_versions_rename_id(bmain, ID_BR, "Draw Weight", "Weight Draw");
|
||||
|
||||
/* Identifier generation for simulation node sockets changed.
|
||||
* Update identifiers so links are not removed during validation. */
|
||||
* Update identifiers so links are not removed during validation.
|
||||
* This only affects files that have been created using simulation nodes before they were first
|
||||
* officially released. */
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "NodeSimulationItem", "int", "identifier")) {
|
||||
static auto set_socket_identifiers =
|
||||
[](bNode *node, const bNode *output_node, int extra_outputs) {
|
||||
|
|
|
@ -1596,19 +1596,21 @@ typedef struct NodeGeometryUVUnwrap {
|
|||
uint8_t method;
|
||||
} NodeGeometryUVUnwrap;
|
||||
|
||||
/* TODO: Add RAII */
|
||||
typedef struct NodeSimulationItem {
|
||||
char *name;
|
||||
/* #eNodeSocketDatatype. */
|
||||
/* TODO: Use a different enum instead to support Byte colors, etc. */
|
||||
/** #eNodeSocketDatatype. */
|
||||
short socket_type;
|
||||
/** #eAttrDomain. */
|
||||
short attribute_domain;
|
||||
/* Generates unique identifier for sockets. */
|
||||
/**
|
||||
* Generates unique identifier for sockets which stays the same even when the item order or
|
||||
* names change.
|
||||
*/
|
||||
int identifier;
|
||||
} NodeSimulationItem;
|
||||
|
||||
typedef struct NodeGeometrySimulationInput {
|
||||
/** bNode.identifier of the corresponding output node. */
|
||||
int32_t output_node_id;
|
||||
} NodeGeometrySimulationInput;
|
||||
|
||||
|
@ -1616,7 +1618,7 @@ typedef struct NodeGeometrySimulationOutput {
|
|||
NodeSimulationItem *items;
|
||||
int items_num;
|
||||
int active_index;
|
||||
/* Number to give unique IDs to state items. */
|
||||
/** Number to give unique IDs to state items. */
|
||||
int next_identifier;
|
||||
int _pad;
|
||||
|
||||
|
|
|
@ -4134,7 +4134,7 @@ static void rna_SimulationStateItem_color_get(PointerRNA *ptr, float *values)
|
|||
NodeSimulationItem *item = (NodeSimulationItem *)ptr->data;
|
||||
|
||||
const char *socket_type_idname = nodeStaticSocketType(item->socket_type, 0);
|
||||
node_type_draw_color(socket_type_idname, values);
|
||||
ED_node_type_draw_color(socket_type_idname, values);
|
||||
}
|
||||
|
||||
static PointerRNA rna_NodeGeometrySimulationInput_paired_output_get(PointerRNA *ptr)
|
||||
|
@ -4221,8 +4221,8 @@ static void rna_NodeGeometrySimulationOutput_items_move(
|
|||
{
|
||||
NodeGeometrySimulationOutput *sim = (NodeGeometrySimulationOutput *)node->storage;
|
||||
|
||||
if (from_index < 0 || from_index >= sim->items_num || to_index < 0 ||
|
||||
to_index >= sim->items_num) {
|
||||
if (from_index < 0 || from_index >= sim->items_num || to_index < 0 || to_index >= sim->items_num)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,10 +47,12 @@ struct GeoNodesModifierData {
|
|||
/** Optional logger. */
|
||||
geo_eval_log::GeoModifierLog *eval_log = nullptr;
|
||||
|
||||
/** Read-only simulation states around the current frame. */
|
||||
const bke::sim::ModifierSimulationState *current_simulation_state = nullptr;
|
||||
const bke::sim::ModifierSimulationState *prev_simulation_state = nullptr;
|
||||
const bke::sim::ModifierSimulationState *next_simulation_state = nullptr;
|
||||
float simulation_state_mix_factor = 0.0f;
|
||||
/** Used when the evaluation should create a new simulation state. */
|
||||
bke::sim::ModifierSimulationState *current_simulation_state_for_write = nullptr;
|
||||
float simulation_time_delta = 0.0f;
|
||||
|
||||
|
|
|
@ -22,8 +22,6 @@ struct bNodeTree;
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void node_type_draw_color(const char *idname, float *r_color);
|
||||
|
||||
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
struct bNodeSocketTemplate *stemp,
|
||||
|
|
|
@ -34,11 +34,11 @@ std::string socket_identifier_for_simulation_item(const NodeSimulationItem &item
|
|||
static std::unique_ptr<SocketDeclaration> socket_declaration_for_simulation_item(
|
||||
const NodeSimulationItem &item, const eNodeSocketInOut in_out, const int index)
|
||||
{
|
||||
BLI_assert(NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
eNodeSocketDatatype(item.socket_type)));
|
||||
const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
|
||||
BLI_assert(NOD_geometry_simulation_output_item_socket_type_supported(socket_type));
|
||||
|
||||
std::unique_ptr<SocketDeclaration> decl;
|
||||
switch (eNodeSocketDatatype(item.socket_type)) {
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
decl = std::make_unique<decl::Float>();
|
||||
decl->input_field_type = InputSocketFieldType::IsSupported;
|
||||
|
@ -179,7 +179,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
switch (socket_type) {
|
||||
case SOCK_GEOMETRY: {
|
||||
if (const auto *geo_state_item =
|
||||
dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(&state_item)) {
|
||||
dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(&state_item))
|
||||
{
|
||||
GeometrySet *geometry = new (r_output_value) GeometrySet(geo_state_item->geometry());
|
||||
geometries.append(geometry);
|
||||
}
|
||||
|
@ -196,7 +197,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
const fn::ValueOrFieldCPPType &value_or_field_type =
|
||||
*fn::ValueOrFieldCPPType::get_from_self(cpp_type);
|
||||
if (const auto *primitive_state_item =
|
||||
dynamic_cast<const bke::sim::PrimitiveSimulationStateItem *>(&state_item)) {
|
||||
dynamic_cast<const bke::sim::PrimitiveSimulationStateItem *>(&state_item))
|
||||
{
|
||||
if (primitive_state_item->type() == value_or_field_type.value) {
|
||||
value_or_field_type.construct_from_value(r_output_value,
|
||||
primitive_state_item->value());
|
||||
|
@ -206,7 +208,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
}
|
||||
}
|
||||
else if (const auto *attribute_state_item =
|
||||
dynamic_cast<const bke::sim::AttributeSimulationStateItem *>(&state_item)) {
|
||||
dynamic_cast<const bke::sim::AttributeSimulationStateItem *>(&state_item))
|
||||
{
|
||||
AnonymousAttributeIDPtr attribute_id = MEM_new<NodeAnonymousAttributeID>(
|
||||
__func__,
|
||||
self_object,
|
||||
|
@ -226,7 +229,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
}
|
||||
case SOCK_STRING: {
|
||||
if (const auto *string_state_item =
|
||||
dynamic_cast<const bke::sim::StringSimulationStateItem *>(&state_item)) {
|
||||
dynamic_cast<const bke::sim::StringSimulationStateItem *>(&state_item))
|
||||
{
|
||||
new (r_output_value) ValueOrField<std::string>(string_state_item->value());
|
||||
}
|
||||
else {
|
||||
|
@ -246,7 +250,8 @@ void simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_i
|
|||
for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
|
||||
GEO_COMPONENT_TYPE_CURVE,
|
||||
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
||||
GEO_COMPONENT_TYPE_INSTANCES}) {
|
||||
GEO_COMPONENT_TYPE_INSTANCES})
|
||||
{
|
||||
if (!geometry->has(type)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -415,6 +420,7 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
|
|||
modifier_data.current_simulation_state->get_zone_state(zone_id) :
|
||||
nullptr;
|
||||
if (eval_data.is_first_evaluation && current_zone_state != nullptr) {
|
||||
/* Common case when data is cached already. */
|
||||
this->output_cached_state(
|
||||
params, *modifier_data.self_object, *user_data.compute_context, *current_zone_state);
|
||||
return;
|
||||
|
@ -426,6 +432,8 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
|
|||
modifier_data.prev_simulation_state->get_zone_state(zone_id) :
|
||||
nullptr;
|
||||
if (prev_zone_state == nullptr) {
|
||||
/* There is no previous simulation state and we also don't create a new one, so just output
|
||||
* defaults. */
|
||||
params.set_default_remaining_outputs();
|
||||
return;
|
||||
}
|
||||
|
@ -434,10 +442,12 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
|
|||
modifier_data.next_simulation_state->get_zone_state(zone_id) :
|
||||
nullptr;
|
||||
if (next_zone_state == nullptr) {
|
||||
/* Output the last cached simulation state. */
|
||||
this->output_cached_state(
|
||||
params, *modifier_data.self_object, *user_data.compute_context, *prev_zone_state);
|
||||
return;
|
||||
}
|
||||
/* A previous and next frame is cached already, but the current frame is not. */
|
||||
this->output_mixed_cached_state(params,
|
||||
*modifier_data.self_object,
|
||||
*user_data.compute_context,
|
||||
|
@ -512,7 +522,8 @@ bke::sim::SimulationZoneID get_simulation_zone_id(const ComputeContext &compute_
|
|||
{
|
||||
bke::sim::SimulationZoneID zone_id;
|
||||
for (const ComputeContext *context = &compute_context; context != nullptr;
|
||||
context = context->parent()) {
|
||||
context = context->parent())
|
||||
{
|
||||
if (const auto *node_context = dynamic_cast<const bke::NodeGroupComputeContext *>(context)) {
|
||||
zone_id.node_ids.append(node_context->node_id());
|
||||
}
|
||||
|
@ -622,7 +633,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
if (link->tonode == node) {
|
||||
if (link->tosock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->fromsock)) {
|
||||
&storage, link->fromnode, link->fromsock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->tosock = nodeFindSocket(
|
||||
node, SOCK_IN, socket_identifier_for_simulation_item(*item).c_str());
|
||||
|
@ -636,7 +648,8 @@ static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
|
|||
BLI_assert(link->fromnode == node);
|
||||
if (link->fromsock->identifier == StringRef("__extend__")) {
|
||||
if (const NodeSimulationItem *item = NOD_geometry_simulation_output_add_item_from_socket(
|
||||
&storage, link->fromnode, link->tosock)) {
|
||||
&storage, link->fromnode, link->tosock))
|
||||
{
|
||||
update_node_declaration_and_sockets(*ntree, *node);
|
||||
link->fromsock = nodeFindSocket(
|
||||
node, SOCK_OUT, socket_identifier_for_simulation_item(*item).c_str());
|
||||
|
@ -777,8 +790,8 @@ NodeSimulationItem *NOD_geometry_simulation_output_insert_item(NodeGeometrySimul
|
|||
const char *name,
|
||||
int index)
|
||||
{
|
||||
if (!NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
eNodeSocketDatatype(socket_type))) {
|
||||
if (!NOD_geometry_simulation_output_item_socket_type_supported(eNodeSocketDatatype(socket_type)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,6 @@ using namespace blender;
|
|||
using blender::fn::ValueOrField;
|
||||
using blender::nodes::SocketDeclarationPtr;
|
||||
|
||||
extern "C" void ED_node_type_draw_color(const char *idname, float *r_color);
|
||||
|
||||
void node_type_draw_color(const char *idname, float *r_color)
|
||||
{
|
||||
ED_node_type_draw_color(idname, r_color);
|
||||
}
|
||||
|
||||
struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree,
|
||||
struct bNode *node,
|
||||
struct bNodeSocketTemplate *stemp,
|
||||
|
|
Loading…
Reference in New Issue