Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2021-03-19 15:59:56 +0300
committerHans Goudey <h.goudey@me.com>2021-03-19 15:59:56 +0300
commit97b83b6a6781b613268d8d65244b96583bf2a981 (patch)
tree6cd0dbf8f99b24e95050656df1dda8dfbfff4dc3
parenta7f427074873ecf5a11a7e866174f22b47bb26a0 (diff)
Geometry Nodes: Implicit interpolations to and from the edge domain
This patch adds the remaining 6 interpolations for mesh domains. The new interpolations are: - Corner / point / polygon to edge - Edge to corner / point / polygon After this it is possible to adapt an attribute to and from every mesh domain. This is simple to test with the "Attribute Convert" node. Though, as a note for the future, there are still some improvements possible to the interpolations, like lazily calculating values for the interpolations where it's possible, and slightly improving the algorithms used for some interpolations, like using corner angles for polygon to point. Differential Revision: https://developer.blender.org/D10765
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc257
1 files changed, 257 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 8ee2142799d..eee7c2ff09e 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -297,6 +297,47 @@ static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh,
}
template<typename T>
+static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
+ Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+
+ /* For every edge, mix values from the two adjacent corners (the current and next corner). */
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_next = (loop_index + 1) % poly.totloop;
+ const MLoop &loop = mesh.mloop[loop_index];
+ const int edge_index = loop.e;
+ mixer.mix_in(edge_index, old_values[loop_index]);
+ mixer.mix_in(edge_index, old_values[loop_index_next]);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totedge);
+ adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh,
Span<T> old_values,
MutableSpan<T> r_values)
@@ -365,6 +406,42 @@ static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh,
return new_attribute;
}
+template<typename T>
+void adapt_mesh_domain_polygon_to_edge_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ const T value = old_values[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ mixer.mix_in(loop.e, value);
+ }
+ }
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_polygon_to_edge(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totedge);
+ adapt_mesh_domain_polygon_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
/**
* \note Theoretically this interpolation does not need to compute all values at once.
* However, doing that makes the implementation simpler, and this can be optimized in the future if
@@ -406,6 +483,162 @@ static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh,
return new_attribute;
}
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totedge);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int edge_index : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[edge_index];
+ mixer.mix_in(edge_index, old_values[edge.v1]);
+ mixer.mix_in(edge_index, old_values[edge.v2]);
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totedge);
+ adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totloop);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+
+ /* For every corner, mix the values from the adjacent edges on the polygon. */
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_prev = (loop_index - 1) % poly.totloop;
+ const MLoop &loop = mesh.mloop[loop_index];
+ const MLoop &loop_prev = mesh.mloop[loop_index_prev];
+ mixer.mix_in(loop_index, old_values[loop.e]);
+ mixer.mix_in(loop_index, old_values[loop_prev.e]);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totloop);
+ adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+template<typename T>
+static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totvert);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int edge_index : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[edge_index];
+ const T value = old_values[edge_index];
+ mixer.mix_in(edge.v1, value);
+ mixer.mix_in(edge.v2, value);
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totvert);
+ adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
+/**
+ * \note Theoretically this interpolation does not need to compute all values at once.
+ * However, doing that makes the implementation simpler, and this can be optimized in the future if
+ * only some values are required.
+ */
+template<typename T>
+static void adapt_mesh_domain_edge_to_polygon_impl(const Mesh &mesh,
+ const Span<T> old_values,
+ MutableSpan<T> r_values)
+{
+ BLI_assert(r_values.size() == mesh.totpoly);
+ attribute_math::DefaultMixer<T> mixer(r_values);
+
+ for (const int poly_index : IndexRange(mesh.totpoly)) {
+ const MPoly &poly = mesh.mpoly[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const MLoop &loop = mesh.mloop[loop_index];
+ mixer.mix_in(poly_index, old_values[loop.e]);
+ }
+ }
+
+ mixer.finalize();
+}
+
+static ReadAttributePtr adapt_mesh_domain_edge_to_polygon(const Mesh &mesh,
+ ReadAttributePtr attribute)
+{
+ ReadAttributePtr new_attribute;
+ const CustomDataType data_type = attribute->custom_data_type();
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ Array<T> values(mesh.totpoly);
+ adapt_mesh_domain_edge_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values);
+ new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
+ std::move(values));
+ }
+ });
+ return new_attribute;
+}
+
} // namespace blender::bke
ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
@@ -429,7 +662,10 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_EDGE:
+ return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
default:
+ BLI_assert(false);
break;
}
break;
@@ -440,7 +676,10 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
case ATTR_DOMAIN_POLYGON:
return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_EDGE:
+ return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
default:
+ BLI_assert(false);
break;
}
break;
@@ -451,12 +690,30 @@ ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attr
return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute));
case ATTR_DOMAIN_CORNER:
return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_EDGE:
+ return blender::bke::adapt_mesh_domain_polygon_to_edge(*mesh_, std::move(attribute));
default:
+ BLI_assert(false);
+ break;
+ }
+ break;
+ }
+ case ATTR_DOMAIN_EDGE: {
+ switch (new_domain) {
+ case ATTR_DOMAIN_CORNER:
+ return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POINT:
+ return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
+ case ATTR_DOMAIN_POLYGON:
+ return blender::bke::adapt_mesh_domain_edge_to_polygon(*mesh_, std::move(attribute));
+ default:
+ BLI_assert(false);
break;
}
break;
}
default:
+ BLI_assert(false);
break;
}