Blender  V3.3
node_geo_attribute_capture.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "UI_interface.h"
4 #include "UI_resources.h"
5 
6 #include "BKE_attribute_math.hh"
7 
9 
10 #include "node_geometry_util.hh"
11 
13 
15 
17 {
18  b.add_input<decl::Geometry>(N_("Geometry"));
19  b.add_input<decl::Vector>(N_("Value")).supports_field();
20  b.add_input<decl::Float>(N_("Value"), "Value_001").supports_field();
21  b.add_input<decl::Color>(N_("Value"), "Value_002").supports_field();
22  b.add_input<decl::Bool>(N_("Value"), "Value_003").supports_field();
23  b.add_input<decl::Int>(N_("Value"), "Value_004").supports_field();
24 
25  b.add_output<decl::Geometry>(N_("Geometry"));
26  b.add_output<decl::Vector>(N_("Attribute")).field_source();
27  b.add_output<decl::Float>(N_("Attribute"), "Attribute_001").field_source();
28  b.add_output<decl::Color>(N_("Attribute"), "Attribute_002").field_source();
29  b.add_output<decl::Bool>(N_("Attribute"), "Attribute_003").field_source();
30  b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source();
31 }
32 
33 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
34 {
35  uiLayoutSetPropSep(layout, true);
36  uiLayoutSetPropDecorate(layout, false);
37  uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
38  uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
39 }
40 
42 {
43  NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
44  data->data_type = CD_PROP_FLOAT;
45  data->domain = ATTR_DOMAIN_POINT;
46 
47  node->storage = data;
48 }
49 
51 {
52  const NodeGeometryAttributeCapture &storage = node_storage(*node);
53  const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
54 
55  bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
56  bNodeSocket *socket_value_vector = socket_value_geometry->next;
57  bNodeSocket *socket_value_float = socket_value_vector->next;
58  bNodeSocket *socket_value_color4f = socket_value_float->next;
59  bNodeSocket *socket_value_boolean = socket_value_color4f->next;
60  bNodeSocket *socket_value_int32 = socket_value_boolean->next;
61 
62  nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3);
63  nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT);
64  nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR);
65  nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL);
66  nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32);
67 
68  bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first;
69  bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next;
70  bNodeSocket *out_socket_value_float = out_socket_value_vector->next;
71  bNodeSocket *out_socket_value_color4f = out_socket_value_float->next;
72  bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next;
73  bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next;
74 
75  nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3);
76  nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT);
77  nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR);
78  nodeSetSocketAvailability(ntree, out_socket_value_boolean, data_type == CD_PROP_BOOL);
79  nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32);
80 }
81 
83 {
84  const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
85  search_link_ops_for_declarations(params, declaration.inputs().take_front(1));
86  search_link_ops_for_declarations(params, declaration.outputs().take_front(1));
87 
88  const bNodeType &node_type = params.node_type();
89  const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
90  (eNodeSocketDatatype)params.other_socket().type);
91  if (type && *type != CD_PROP_STRING) {
92  if (params.in_out() == SOCK_OUT) {
93  params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
94  bNode &node = params.add_node(node_type);
95  node_storage(node).data_type = *type;
96  params.update_and_connect_available_socket(node, "Attribute");
97  });
98  }
99  else {
100  params.add_item(IFACE_("Value"), [node_type, type](LinkSearchOpParams &params) {
101  bNode &node = params.add_node(node_type);
102  node_storage(node).data_type = *type;
103  params.update_and_connect_available_socket(node, "Value");
104  });
105  }
106  }
107 }
108 
110  const AttributeIDRef &attribute_id,
111  const eAttrDomain domain,
112  const GField &field)
113 {
114  const int domain_size = component.attribute_domain_size(domain);
115  if (domain_size == 0) {
116  return;
117  }
118  GeometryComponentFieldContext field_context{component, domain};
119  MutableAttributeAccessor attributes = *component.attributes_for_write();
120  const IndexMask mask{IndexMask(domain_size)};
121 
123  GAttributeWriter output_attribute = attributes.lookup_or_add_for_write(
124  attribute_id, domain, data_type);
125  if (!output_attribute) {
126  return;
127  }
128 
129  fn::FieldEvaluator evaluator{field_context, &mask};
130  evaluator.add_with_destination(field, output_attribute.varray);
131  evaluator.evaluate();
132 
133  output_attribute.finish();
134 }
135 
137 {
138  switch (data_type) {
139  case CD_PROP_FLOAT:
140  return "_001";
141  case CD_PROP_INT32:
142  return "_004";
143  case CD_PROP_COLOR:
144  return "_002";
145  case CD_PROP_BOOL:
146  return "_003";
147  case CD_PROP_FLOAT3:
148  return "";
149  default:
151  return "";
152  }
153 }
154 
156 {
157  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
158 
159  if (!params.output_is_required("Geometry")) {
160  params.error_message_add(
162  TIP_("The attribute output can not be used without the geometry output"));
163  params.set_default_remaining_outputs();
164  return;
165  }
166 
167  const NodeGeometryAttributeCapture &storage = node_storage(params.node());
168  const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
169  const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
170 
171  const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
172 
173  if (!params.output_is_required(output_identifier)) {
174  params.set_output("Geometry", geometry_set);
175  return;
176  }
177 
178  const std::string input_identifier = "Value" + identifier_suffix(data_type);
179  GField field;
180 
181  switch (data_type) {
182  case CD_PROP_FLOAT:
183  field = params.get_input<Field<float>>(input_identifier);
184  break;
185  case CD_PROP_FLOAT3:
186  field = params.get_input<Field<float3>>(input_identifier);
187  break;
188  case CD_PROP_COLOR:
189  field = params.get_input<Field<ColorGeometry4f>>(input_identifier);
190  break;
191  case CD_PROP_BOOL:
192  field = params.get_input<Field<bool>>(input_identifier);
193  break;
194  case CD_PROP_INT32:
195  field = params.get_input<Field<int>>(input_identifier);
196  break;
197  default:
198  break;
199  }
200 
201  WeakAnonymousAttributeID anonymous_id{"Attribute"};
202  const CPPType &type = field.cpp_type();
203 
204  /* Run on the instances component separately to only affect the top level of instances. */
205  if (domain == ATTR_DOMAIN_INSTANCE) {
206  if (geometry_set.has_instances()) {
209  try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
210  }
211  }
212  else {
213  static const Array<GeometryComponentType> types = {
215 
216  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
217  for (const GeometryComponentType type : types) {
218  if (geometry_set.has(type)) {
219  GeometryComponent &component = geometry_set.get_component_for_write(type);
220  try_capture_field_on_geometry(component, anonymous_id.get(), domain, field);
221  }
222  }
223  });
224  }
225 
226  GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>(
227  std::move(anonymous_id), type, params.attribute_producer_name())};
228 
229  switch (data_type) {
230  case CD_PROP_FLOAT: {
231  params.set_output(output_identifier, Field<float>(output_field));
232  break;
233  }
234  case CD_PROP_FLOAT3: {
235  params.set_output(output_identifier, Field<float3>(output_field));
236  break;
237  }
238  case CD_PROP_COLOR: {
239  params.set_output(output_identifier, Field<ColorGeometry4f>(output_field));
240  break;
241  }
242  case CD_PROP_BOOL: {
243  params.set_output(output_identifier, Field<bool>(output_field));
244  break;
245  }
246  case CD_PROP_INT32: {
247  params.set_output(output_identifier, Field<int>(output_field));
248  break;
249  }
250  default:
251  break;
252  }
253 
254  params.set_output("Geometry", geometry_set);
255 }
256 
257 } // namespace blender::nodes::node_geo_attribute_capture_cc
258 
260 {
262 
263  static bNodeType ntype;
264 
266  &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE);
267  node_type_storage(&ntype,
268  "NodeGeometryAttributeCapture",
277  nodeRegisterType(&ntype);
278 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_INSTANCE
Definition: BKE_attribute.h:32
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ GEO_COMPONENT_TYPE_CURVE
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4443
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
Definition: node.cc:3664
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
#define GEO_NODE_CAPTURE_ATTRIBUTE
Definition: BKE_node.h:1422
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define UNUSED(x)
#define TIP_(msgid)
#define IFACE_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
eCustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ CD_PROP_BOOL
@ CD_PROP_STRING
@ SOCK_OUT
eNodeSocketDatatype
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
in reality light always falls off quadratically Particle Info
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
GAttributeWriter lookup_or_add_for_write(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
const CPPType & cpp_type() const
Definition: FN_field.hh:122
Span< SocketDeclarationPtr > outputs() const
Span< SocketDeclarationPtr > inputs() const
OperationNode * node
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char ** types
Definition: makesdna.c:67
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
OwnedAnonymousAttributeID< false > WeakAnonymousAttributeID
eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
Definition: customdata.cc:5337
static void node_update(bNodeTree *ntree, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static StringRefNull identifier_suffix(eCustomDataType data_type)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void try_capture_field_on_geometry(GeometryComponent &component, const AttributeIDRef &attribute_id, const eAttrDomain domain, const GField &field)
std::optional< eCustomDataType > node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
void search_link_ops_for_declarations(GatherLinkSearchOpParams &params, Span< SocketDeclarationPtr > declarations)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_attribute_capture()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
bool has_instances() const
void modify_geometry_sets(ForeachSubGeometryCallback callback)
struct bNodeSocket * next
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition: BKE_node.h:335
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480