Blender  V2.93
node_geo_align_rotation_to_vector.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BLI_math_rotation.h"
18 
19 #include "UI_interface.h"
20 #include "UI_resources.h"
21 
22 #include "node_geometry_util.hh"
23 
25  {SOCK_GEOMETRY, N_("Geometry")},
26  {SOCK_STRING, N_("Factor")},
27  {SOCK_FLOAT, N_("Factor"), 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, PROP_FACTOR},
28  {SOCK_STRING, N_("Vector")},
29  {SOCK_VECTOR, N_("Vector"), 0.0, 0.0, 1.0, 0.0, -FLT_MAX, FLT_MAX, PROP_ANGLE},
30  {-1, ""},
31 };
32 
34  {SOCK_GEOMETRY, N_("Geometry")},
35  {-1, ""},
36 };
37 
39  bContext *UNUSED(C),
40  PointerRNA *ptr)
41 {
42  uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
43  uiLayoutSetPropSep(layout, true);
44  uiLayoutSetPropDecorate(layout, false);
45  uiItemR(layout, ptr, "pivot_axis", 0, IFACE_("Pivot"), ICON_NONE);
46  uiLayout *col = uiLayoutColumn(layout, false);
47  uiItemR(col, ptr, "input_type_factor", 0, IFACE_("Factor"), ICON_NONE);
48  uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
49 }
50 
51 namespace blender::nodes {
52 
54  const FloatReadAttribute &factors,
55  const float3 local_main_axis,
56  MutableSpan<float3> rotations)
57 {
58  for (const int i : IndexRange(vectors.size())) {
59  const float3 vector = vectors[i];
60  if (is_zero_v3(vector)) {
61  continue;
62  }
63 
64  float old_rotation[3][3];
65  eul_to_mat3(old_rotation, rotations[i]);
66  float3 old_axis;
67  mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
68 
69  const float3 new_axis = vector.normalized();
70  float3 rotation_axis = float3::cross_high_precision(old_axis, new_axis);
71  if (is_zero_v3(rotation_axis)) {
72  /* The vectors are linearly dependent, so we fall back to another axis. */
73  rotation_axis = float3::cross_high_precision(old_axis, float3(1, 0, 0));
74  if (is_zero_v3(rotation_axis)) {
75  /* This is now guaranteed to not be zero. */
76  rotation_axis = float3::cross_high_precision(old_axis, float3(0, 1, 0));
77  }
78  }
79 
80  const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
81  const float angle = factors[i] * full_angle;
82 
83  float rotation[3][3];
84  axis_angle_to_mat3(rotation, rotation_axis, angle);
85 
86  float new_rotation_matrix[3][3];
87  mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
88 
89  float3 new_rotation;
90  mat3_to_eul(new_rotation, new_rotation_matrix);
91 
92  rotations[i] = new_rotation;
93  }
94 }
95 
97  const FloatReadAttribute &factors,
98  const float3 local_main_axis,
99  const float3 local_pivot_axis,
100  MutableSpan<float3> rotations)
101 {
102  if (local_main_axis == local_pivot_axis) {
103  /* Can't compute any meaningful rotation angle in this case. */
104  return;
105  }
106 
107  for (const int i : IndexRange(vectors.size())) {
108  const float3 vector = vectors[i];
109  if (is_zero_v3(vector)) {
110  continue;
111  }
112 
113  float old_rotation[3][3];
114  eul_to_mat3(old_rotation, rotations[i]);
115  float3 old_axis;
116  mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
117  float3 pivot_axis;
118  mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
119 
120  float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
121  if (full_angle > M_PI) {
122  /* Make sure the point is rotated as little as possible. */
123  full_angle -= 2.0f * M_PI;
124  }
125  const float angle = factors[i] * full_angle;
126 
127  float rotation[3][3];
128  axis_angle_to_mat3(rotation, pivot_axis, angle);
129 
130  float new_rotation_matrix[3][3];
131  mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
132 
133  float3 new_rotation;
134  mat3_to_eul(new_rotation, new_rotation_matrix);
135 
136  rotations[i] = new_rotation;
137  }
138 }
139 
141  const GeoNodeExecParams &params)
142 {
143  const bNode &node = params.node();
145  node.storage;
146 
147  OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
148  "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
149  if (!rotation_attribute) {
150  return;
151  }
152  MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
153 
154  FloatReadAttribute factors = params.get_input_attribute<float>(
155  "Factor", component, ATTR_DOMAIN_POINT, 1.0f);
156  Float3ReadAttribute vectors = params.get_input_attribute<float3>(
157  "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
158 
159  float3 local_main_axis{0, 0, 0};
160  local_main_axis[storage.axis] = 1;
162  align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations);
163  }
164  else {
165  float3 local_pivot_axis{0, 0, 0};
166  local_pivot_axis[storage.pivot_axis - 1] = 1;
167  align_rotations_fixed_pivot(vectors, factors, local_main_axis, local_pivot_axis, rotations);
168  }
169 
170  rotation_attribute.apply_span_and_save();
171 }
172 
174 {
175  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
176 
177  geometry_set = geometry_set_realize_instances(geometry_set);
178 
179  if (geometry_set.has<MeshComponent>()) {
181  }
182  if (geometry_set.has<PointCloudComponent>()) {
184  params);
185  }
186 
187  params.set_output("Geometry", geometry_set);
188 }
189 
191 {
194 
198 
199  node->storage = node_storage;
200 }
201 
203 {
205  node->storage;
207  *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
209  *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
210 }
211 
212 } // namespace blender::nodes
213 
215 {
216  static bNodeType ntype;
217 
218  geo_node_type_base(&ntype,
220  "Align Rotation to Vector",
222  0);
227  node_type_storage(&ntype,
228  "NodeGeometryAlignRotationToVector",
233  nodeRegisterType(&ntype);
234 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4623
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4559
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
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:4599
#define GEO_NODE_ALIGN_ROTATION_TO_VECTOR
Definition: BKE_node.h:1394
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define M_PI
Definition: BLI_math_base.h:38
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:901
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:391
void eul_to_mat3(float mat[3][3], const float eul[3])
void mat3_to_eul(float eul[3], const float mat[3][3])
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle)
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:551
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
#define UNUSED(x)
#define IFACE_(msgid)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
@ CD_PROP_FLOAT3
@ GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO
@ GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_STRING
GeometryNodeAttributeInputMode
@ GEO_NODE_ATTRIBUTE_INPUT_VECTOR
@ GEO_NODE_ATTRIBUTE_INPUT_FLOAT
@ PROP_ANGLE
Definition: RNA_types.h:132
@ PROP_FACTOR
Definition: RNA_types.h:131
#define C
Definition: RandGen.cpp:39
@ UI_ITEM_R_EXPAND
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
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)
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
OperationNode * node
bNodeTree * ntree
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
TypedReadAttribute< float > FloatReadAttribute
TypedReadAttribute< float3 > Float3ReadAttribute
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
static void geo_node_align_rotation_to_vector_update(bNodeTree *UNUSED(ntree), bNode *node)
static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
void update_attribute_input_socket_availabilities(bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available)
static void align_rotations_fixed_pivot(const Float3ReadAttribute &vectors, const FloatReadAttribute &factors, const float3 local_main_axis, const float3 local_pivot_axis, MutableSpan< float3 > rotations)
static void align_rotations_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors, const FloatReadAttribute &factors, const float3 local_main_axis, MutableSpan< float3 > rotations)
static bNodeSocketTemplate geo_node_align_rotation_to_vector_out[]
void register_node_type_geo_align_rotation_to_vector()
static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static bNodeSocketTemplate geo_node_align_rotation_to_vector_in[]
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:67
void node_free_standard_storage(bNode *node)
Definition: node_util.c:55
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:253
static float3 cross_high_precision(const float3 &a, const float3 &b)
Definition: BLI_float3.hh:241
PointerRNA * ptr
Definition: wm_files.c:3157