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:
Diffstat (limited to 'source/blender/blenkernel/intern/geometry_component_mesh.cc')
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc216
1 files changed, 131 insertions, 85 deletions
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 715c7d6c743..d148d59a48b 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -13,6 +13,9 @@
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+
+#include "FN_multi_function_builder.hh"
#include "attribute_access_intern.hh"
@@ -211,27 +214,30 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
}
/* Deselect loose vertices without corners that are still selected from the 'true' default. */
- for (const int vert_index : IndexRange(mesh.totvert)) {
- if (loose_verts[vert_index]) {
- r_values[vert_index] = false;
+ /* The record fact says that the value is true.
+ *Writing to the array from different threads is okay because each thread sets the same value. */
+ threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
+ for (const int vert_index : range) {
+ if (loose_verts[vert_index]) {
+ r_values[vert_index] = false;
+ }
}
- }
+ });
}
static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totvert);
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
/* We compute all interpolated values at once, because for this interpolation, one has to
* iterate over all loops anyway. */
- Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_corner_to_point_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
/**
@@ -366,16 +372,15 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totedge);
attribute_math::convert_to_static_type(varray.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, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_corner_to_edge_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
template<typename T>
@@ -413,30 +418,29 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- if (old_values[poly_index]) {
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = loops[loop_index];
- const int vert_index = loop.v;
- r_values[vert_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ if (old_values[poly_index]) {
+ const MPoly &poly = polys[poly_index];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ r_values[loop.v] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totvert);
attribute_math::convert_to_static_type(varray.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_face_to_point_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_face_to_point_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
/* Each corner's value is simply a copy of the value at its face. */
@@ -459,16 +463,15 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totloop);
attribute_math::convert_to_static_type(varray.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_face_to_corner_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_face_to_corner_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
template<typename T>
@@ -504,30 +507,29 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
const Span<MLoop> loops = mesh.loops();
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- if (old_values[poly_index]) {
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = loops[loop_index];
- const int edge_index = loop.e;
- r_values[edge_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ if (old_values[poly_index]) {
+ const MPoly &poly = polys[poly_index];
+ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
+ r_values[loop.e] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totedge);
attribute_math::convert_to_static_type(varray.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_face_to_edge_impl<T>(mesh, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_face_to_edge_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray)
@@ -622,7 +624,7 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
/* For every corner, mix the values from the adjacent edges on the face. */
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
+ const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index);
const MLoop &loop = loops[loop_index];
const MLoop &loop_prev = loops[loop_index_prev];
mixer.mix_in(loop_index, old_values[loop.e]);
@@ -645,31 +647,32 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
r_values.fill(false);
- for (const int poly_index : polys.index_range()) {
- const MPoly &poly = polys[poly_index];
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const int loop_index_prev = loop_index - 1 + (loop_index == poly.loopstart) * poly.totloop;
- const MLoop &loop = loops[loop_index];
- const MLoop &loop_prev = loops[loop_index_prev];
- if (old_values[loop.e] && old_values[loop_prev.e]) {
- r_values[loop_index] = true;
+ threading::parallel_for(polys.index_range(), 2048, [&](const IndexRange range) {
+ for (const int poly_index : range) {
+ const MPoly &poly = polys[poly_index];
+ for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
+ const int loop_index_prev = mesh_topology::previous_poly_loop(poly, loop_index);
+ const MLoop &loop = loops[loop_index];
+ const MLoop &loop_prev = loops[loop_index_prev];
+ if (old_values[loop.e] && old_values[loop_prev.e]) {
+ r_values[loop_index] = true;
+ }
}
}
- }
+ });
}
static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totloop);
attribute_math::convert_to_static_type(varray.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, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_edge_to_corner_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
template<typename T>
@@ -701,28 +704,31 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
BLI_assert(r_values.size() == mesh.totvert);
const Span<MEdge> edges = mesh.edges();
+ /* Multiple threads can write to the same index here, but they are only
+ * writing true, and writing to single bytes is expected to be threadsafe. */
r_values.fill(false);
- for (const int edge_index : edges.index_range()) {
- const MEdge &edge = edges[edge_index];
- if (old_values[edge_index]) {
- r_values[edge.v1] = true;
- r_values[edge.v2] = true;
+ threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
+ for (const int edge_index : range) {
+ if (old_values[edge_index]) {
+ const MEdge &edge = edges[edge_index];
+ r_values[edge.v1] = true;
+ r_values[edge.v2] = true;
+ }
}
- }
+ });
}
static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray)
{
- GVArray new_varray;
+ GArray<> values(varray.type(), mesh.totvert);
attribute_math::convert_to_static_type(varray.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, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
+ adapt_mesh_domain_edge_to_point_impl<T>(
+ mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
}
});
- return new_varray;
+ return GVArray::ForGArray(std::move(values));
}
static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray)
@@ -770,6 +776,30 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
} // namespace blender::bke
+static bool can_simple_adapt_for_single(const eAttrDomain from_domain, const eAttrDomain to_domain)
+{
+ /* For some domain combinations, a single value will always map directly. For others, there may
+ * be loose elements on the result domain that should have the default value rather than the
+ * single value from the source. */
+ switch (from_domain) {
+ case ATTR_DOMAIN_POINT:
+ /* All other domains are always connected to points. */
+ return true;
+ case ATTR_DOMAIN_EDGE:
+ /* There may be loose vertices not connected to edges. */
+ return ELEM(to_domain, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+ case ATTR_DOMAIN_FACE:
+ /* There may be loose vertices or edges not connected to faces. */
+ return to_domain == ATTR_DOMAIN_CORNER;
+ case ATTR_DOMAIN_CORNER:
+ /* Only faces are always connected to corners. */
+ return to_domain == ATTR_DOMAIN_FACE;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+}
+
static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
const blender::GVArray &varray,
const eAttrDomain from_domain,
@@ -784,6 +814,14 @@ static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
if (from_domain == to_domain) {
return varray;
}
+ if (varray.is_single()) {
+ if (can_simple_adapt_for_single(from_domain, to_domain)) {
+ BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), value);
+ varray.get_internal_single(value);
+ return blender::GVArray::ForSingle(
+ varray.type(), mesh.attributes().domain_size(to_domain), value);
+ }
+ }
switch (from_domain) {
case ATTR_DOMAIN_CORNER: {
@@ -902,14 +940,14 @@ static void set_loop_uv(MLoopUV &uv, float2 co)
copy_v2_v2(uv.uv, co);
}
-static float get_crease(const MEdge &edge)
+static float get_crease(const float &crease)
{
- return edge.crease / 255.0f;
+ return crease;
}
-static void set_crease(MEdge &edge, float value)
+static void set_crease(float &crease, const float value)
{
- edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
+ crease = std::clamp(value, 0.0f, 1.0f);
}
class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
@@ -1130,17 +1168,17 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
- GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final
+ GAttributeWriter try_get_for_write(void * /*owner*/) const final
{
return {};
}
- bool try_delete(void *UNUSED(owner)) const final
+ bool try_delete(void * /*owner*/) const final
{
return false;
}
- bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void * /*owner*/, const AttributeInit & /*initializer*/) const final
{
return false;
}
@@ -1217,6 +1255,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
make_array_write_attribute<int>,
nullptr);
+ static const fn::CustomMF_SI_SO<int, int> material_index_clamp{
+ "Material Index Validate",
+ [](int value) {
+ /* Use #short for the maximum since many areas still use that type for indices. */
+ return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider material_index("material_index",
ATTR_DOMAIN_FACE,
CD_PROP_INT32,
@@ -1227,7 +1272,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
face_access,
make_array_read_attribute<int>,
make_array_write_attribute<int>,
- nullptr);
+ nullptr,
+ AttributeValidator{&material_index_clamp});
static BuiltinCustomDataLayerProvider shade_smooth(
"shade_smooth",
@@ -1246,13 +1292,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
"crease",
ATTR_DOMAIN_EDGE,
CD_PROP_FLOAT,
- CD_MEDGE,
- BuiltinAttributeProvider::NonCreatable,
+ CD_CREASE,
+ BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
+ BuiltinAttributeProvider::Deletable,
edge_access,
- make_derived_read_attribute<MEdge, float, get_crease>,
- make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
+ make_array_read_attribute<float>,
+ make_derived_write_attribute<float, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(
@@ -1302,7 +1348,7 @@ static AttributeAccessorFunctions get_mesh_accessor_functions()
return 0;
}
};
- fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ fn.domain_supported = [](const void * /*owner*/, const eAttrDomain domain) {
return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
};
fn.adapt_domain = [](const void *owner,