In 157e7e0351 edge calculation was updated to
propagate attributes, but the manifold boolean propagates
edge attributes itself. It seems this causes some issues where
boolean attributes get invalid values, which I discovered while
developing #148063. I didn't investigate too deeply because
I'm going to have to restructure this code for #122398 anyway.
Pull Request: https://projects.blender.org/blender/blender/pulls/148096
Mesh invariants imply that edges and faces must be unique, so things
like reversed edges or duplicate faces with equal vertices are invalid.
For this reason, every time we generate new elements we have to ensure
that all new elements are unique between each other and already existing
elements. The recent refactor (ea875f6f32) introduced a new
algorithm to generate new mesh elements, and deduplication of new
elements was also a part of it. The problem is that the deduplication
only guaranteed that the original elements and new elements don't
overlap; deduplication between each new elements is not complete.
To solve the problem both new triangles and new edges have to be
deduplicated, even if there is no duplicates. Just to know this we have
to build a hash sets.
Triangle deduplication is a special part of the triangulation code,
but edges already handled elsewhere in the code base.
This refactor fixes this by replacing the original approach with one
which guarantees distinct faces and edges in the result.
Unfortunately, this fix increases runtime of the node 10x for a simple
cube with 500-vertex sides. It should be possible to make the
performance better again, but that requires more work.
Other work had to be done to enable this, so this depends on:
- [x] 157e7e0351
- [x] fa8574b80b
Co-authored-by: Hans Goudey <hans@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/147634
Split the result mesh generation to work into two loops. The first loop
builds topology maps used for propagating attribute values, and the next
loop mixes attribute values with those maps. This has a few benefits:
The propagation can be done in parallel, and the topology mapping code
can get simpler. Also, we reduce the overhead that comes with iterating
over all attributes for every single element. Overall I didn't measure
a large performance difference though, because the new code has the
downside of needing to allocate two more arrays.
There is a small difference of a propagated byte color (250 vs. 251) in
the geometry nodes test due to a subtle difference in the mixing
implementation.
Part of #122398.
Pull Request: https://projects.blender.org/blender/blender/pulls/147367
Support sync selection in the UV editor, with face-corner selection,
so it's possible to select individual UV vertices/edges in the UV editor
without UV's attached to the same underlying edge also becoming selected.
There is limited support for maintaining the UV selection when selecting
from the 3D viewport, common operations such as picking &
box/circle/lasso select support this, however other selection operations
such as "Select Random" or "Select Similar" will clear this data,
causing all UV's connected to selected mesh elements to become selected.
We may add support for additional operators as needed.
Details:
- UV Sync Selection is now enabled by default.
- In edit-mode the UV selection is stored in BMLoop/BMFace which are
written to custom-data layers when converted to a Mesh.
- To avoid unnecessary overhead - this data is created on demand.
Operators may clear this data - selecting all or none do so,
as there is no reason to store this data for a uniform selection.
- The Python API includes functions to synchronize the selection to/from
UV's as well as flushing based on the mode.
- Python scripts that manipulate the selection will either need to clear
this synchronized state or maintain it.
See:
- Design task: #78393.
- Implementation task: #131642.
Ref !138197
Use the same rules as the realize instances node to make sure that
free and tangent-space custom normals aren't joined together with
implicit conversions and that there is as little data loss as possible
when joining combinations of no custom normals, free normals, etc.
Pull Request: https://projects.blender.org/blender/blender/pulls/147241
This patch swap position attribute initialization and edge construction
of boolean result. Logic is what both of these steps are last, all
future code do not build mesh topology but only maintain user
attributes. So at this point mesh already must be valid. But future
change of edge calculation (#132492) code will requer this mesh
validation to be done as part of the step. So when edges will be
calculated mesh must already be built, valid and contains position
attribute.
Pull Request: https://projects.blender.org/blender/blender/pulls/146229
The "id" attribute was built-in on curves (point domain), mesh (point domain)
and instances, but not on e.g. point clouds. This mismatch causes issues because
of the special rules regarding built-in attribute propagation. Furthermore, an
implication of this was that the id attribute had to be an integer attribute on
a specific domain, which is not always ideal.
This patch turns the id attribute into a normal generic attribute, except that
some nodes internally modify this attribute in special ways. This may cause some
compatibility breakage in rare cases, but that can generally be easily fixed by
either removing the id attribute or setting it explicitly on the right domain. I
can't think if a feasible way to avoid this unfortunately.
The internal special cases for the id attributes are generally skipped unless
the attribute is an integer attribute on the point/instance domain.
Pull Request: https://projects.blender.org/blender/blender/pulls/146941
OpenVDB will throw an exception when trying to prune a SDF/Level-Set grid with a
negative background value.
The geometry nodes in this case are constructing a nominal SDF grid from a
generic "density" volume cube. The negative background value results from
processing the background value the same way as all other grid values in the new
field+grid math feature (`blender::nodes::process_background`).
Since any grid can be constructed with a negative background value we have to
check and correct this before calling the OpenVDB prune function.
Pull Request: https://projects.blender.org/blender/blender/pulls/146837
This adds support for `Bézier` and `Catmull Rom` curve types to the
interpolation tool.
When interpolating between to curves of different types, a priority
system is used.
The priorities from highest for lowest are in the order
`NURB`, `Bézier`, `Catmull Rom` and `Polyline`.
The reasoning for this order is that:
- `NURBs` can be degree order 5 or greater, were as `Bézier` is only
order 4.
- `Bézier` can match the form of both `Catmull Rom` and `Polyline`, so
should be higher priority.
- `Catmull Rom` is continuous.
- `Polyline` is the simplest and is not smooth, so it should be last.
Note: This does add some simple `NURBs` interpolation, but proper
handling is more complicated and will be save for a future PR.
Resolves: #141178, #143377, #133948 and #136087
Pull Request: https://projects.blender.org/blender/blender/pulls/145683
Currently attribute names are often added to a hash map that doesn't
maintain the original order. This is convenient for developers but it's
better for users if attributes aren't arbitrarily reordered. Instead,
use `VectorSet` which gives the benefit of a hash map but maintains the
insertion order. The main downside is the loss of O(1) removal which we
benefited from in a few cases. I used string comparison instead for now.
Fixes#144491, #122994
Pull Request: https://projects.blender.org/blender/blender/pulls/145668
The code to find output-to-input edge matching missed a case where
both vertices of the output edge existed in the input, but were in
different input meshes.
The pattern of transforming many position vectors at once is quite
common, both with separate source and result arrays, and when modifying
an array in place. In some cases at least we used a separate function
with a consistent name across files, but there were also many duplicate
parallel transform implementations.
This commit adds these utilities to the BLI_math_matrix.hh API and uses
them where many positions from contiguous arrays are transformed at
once. While there might be a more ideal location for these utilities,
it's consistent with 3936d7a93e, and certainly better
than duplicating them.
This also reduces binary size of my build by 15 KB.
Pull Request: https://projects.blender.org/blender/blender/pulls/145352
This argument is always passed as null. Removing it simplifies the
transition to `AttributeStorage`. Nowadays it seems that most more
complicated interpolation needs are not handled directly by the
CustomData system.
Pull Request: https://projects.blender.org/blender/blender/pulls/145197
Blender grid rendering interprets voxel transforms in such a way that the voxel
values are located at the center of a voxel. This is inconsistent with OpenVDB
where the values are located at the lower corners for the purpose or sampling
and related algorithms.
While it is possible to offset grids when communicating with the OpenVDB
library, this is also error-prone and does not add any major advantage.
Every time a grid is passed to OpenVDB we currently have to take care to
transform by half a voxel to ensure correct sampling weights are used that match
the density displayed by the viewport rendering.
This patch changes volume grid generation, conversion, and rendering code so
that grid transforms match the corner-located values in OpenVDB.
- The volume primitive cube node aligns the grid transform with the location of
the first value, which is now also the same as min/max bounds input of the
node.
- Mesh<->Grid conversion does no longer require offsetting grid transform and
mesh vertices respectively by 0.5 voxels.
- Texture space for viewport rendering is offset by half a voxel, so that it
covers the same area as before and voxel centers remain at the same texture
space locations.
Co-authored-by: Brecht Van Lommel <brecht@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/138449
The semantics of checking "has_value()" (etc.) are much better than
checking for an empty span when dealing with the result of an attribute
lookup. This mainly affects the Bezier curve handle position attributes
currently. Plenty of places assume those attributes exist now. In a
couple places the code is a bit safer now, otherwise it's just a bit
more obvious.
Pull Request: https://projects.blender.org/blender/blender/pulls/144506
Strokes would lose their deform group values after moving them to a
different layer, because `vertex_group_names` weren't transferred to
the newly created `CurvesGeometry` inside `execute_realize_curve_tasks`.
This commit adds another version of `copy_vertex_group_names` for
Curves, and separates the duplicate code into `copy_vertex_group_name`,
which is used by both meshes and curves.
This also fixed strokes losing deform weights in multiple situations, such as:
- When performing a layer merge.
- When applying generative modifiers like Mirror or Array
Pull Request: https://projects.blender.org/blender/blender/pulls/142881
The change changes the way the converted curves are evaluated.
It may be better and a valid choice, but it needs to be considered
more carefully since it would be a breaking change.
Hides Resolution field in "Curve Data" panel if at least one poly curve
is selected. For these curves, the field is ignored. Moreover its value
is `0` for them, for all other curve types minimum is `1`.
Also conversion of `CURVE_TYPE_POLY` to `CURVE_TYPE_NURBS` is fixed to
emit curves of order 2. This gives same shape as input had. Resolution
is set to `1`, because "Curve to Mesh" node ignores curves with
Resolution `0`.
Pull Request: https://projects.blender.org/blender/blender/pulls/144239
Many nodes operate on all the instances that are passed into them. For example,
the Subdivision Surface node subdivides the mesh at the root but also instanced
meshes. This works well for most nodes, but there are a few nodes were the old
`modify_geometry_sets` function was not very well defined and it was tricky to
use correctly.
The fundamental problem was that the behavior is not obvious when a node creates
or modifies instances and how those are integrated with the already existing
instances.
This patch solves this with the following changes:
* Remove the old `GeometrySet::modify_geometry_sets` and related
`*_during_modify` methods.
* Add a new `blender::geometry::foreach_real_geometry` function that is similar
to the old `modify_geometry_sets` but has a more well-defined interface:
* It never passes instances into the callback. So existing instances can't be
modified with it.
* The callback is allowed to create new instances. This will automatically be
merged back with potentially already existing instances. The callback does
not have to worry about accidentally invalidating existing instances like
before.
* A few existing usages used `modify_geometry_sets` to actually modify existing
instances (usually just removing attributes). Those can't use the new
`foreach_real_geometry`, so they just get a custom simple recursive
implementation instead of using a generic function.
Pull Request: https://projects.blender.org/blender/blender/pulls/143898
As part of the addition of free normals, the join geometry and realize
instances nodes were updated to properly join custom normals. When one
mesh input had tangent space normals and another had no custom normals,
I chose to use free custom normals for the output mesh since that has
drastically better performance. However, it turns out users get into
that situation much more often than I expected, and because many areas
still don't support free custom normals very well, and their presense
isn't obvious, this causes confusion.
This commit changes this code to output tangent space custom normals
whenever any of the input meshes have tangent space custom normals.
That also maintains the most information for propagation later, since the
"default" status of (0,0) custom normals is maintained.
Fixes#143368
Pull Request: https://projects.blender.org/blender/blender/pulls/143498
When transforming a geometry, we often apply the transposed inverse
to normals / custom normal data. However, that matrix can still contain
scale from the original matrix. That scale has to be removed so we can
avoid also scaling the normals.
I used the opportunity to remove the duplication between mesh and curves
processing of the custom normals, and to formalize an optimization to
skip the final normalization of each vector if the transform is such
that it isn't necessary. The new functions don't fit beautifully into
their public headers, but I don't know of a better place for them.
Pull Request: https://projects.blender.org/blender/blender/pulls/142896
The "curve_type" attribute in curves geometry is built-in and only valid with
a `int8` type on the `Curves` attribute domain. Adding it with a different type
on instance geometry is fine though, but causes invalid attribute writer access
when realizing the instances.
Pull Request: https://projects.blender.org/blender/blender/pulls/142218
The code added to postprocess the manifold result to remove
extra vertices introduced on edges had a logic bug in it.
It would sometimes dissolve a vertex from a triangle.
I thought that would be very rare and just repeated a vertex to
fill out the triangle, but that leads to a mesh that doesn't validate.
Anyway, my logic to prevent a single vertex from being dissolved from
a triangle was wrong (if the triangle was seen second while looking).
I fixed that, and then the even rarer case of two vertices being
dissolved from a quad showed up. I have prevented all such cases
by a loop that disables all vertex dissolving in faces where it
would leave less than three vertices.
Also added an assert (so, debug-mode only) that the mesh produced
by manifold boolean is valid.
The case of subtracing a plane is handled specially as the
plane is not manifold, but the library has a TrimByPlane function.
The special handling code did not deal with the empty result case
properly.
Also, there was no error return checking from Manifold in this special
case, so that was added.
Also, the general error handling just assumed that any Manifold error
on the inputs was a "not manifold" error, which while probably true,
should not be assumed, so that was fixed too.
To resolve, simply pass the matrix to `is_plane` and transform the
points before creating a plane from them.
NOTE: we also have a crash in main when the plane is "outside" the
target, will report that separately.
Pull Request: https://projects.blender.org/blender/blender/pulls/142336
Fix for unreported issue with Grease Pencil interpolation tool: on cyclic curves
the last point is interpolated between the end points of the curve, especially
noticeable with sequence interpolation.
This required handling a corner case in the curve sample mapping function.
This function is complex and hard to verify with the operator alone, leading to
frequent issues and discovery of yet more corner cases. For this reason i
refactored the sampling function and added new unit tests.
This should help avoid regressions and make it clear how the function is
expected to behave in various corner cases.
The `sample_curve_padded` function has been moved into the geometry module,
since the `sculpt_paint` module does not have tests yet and is intended mostly
for higher-level operator code. The function has been split to separate out the
"reverse" sampling mode, which reduces complexity. Reverse sampling is done by
first reversing the input curve points, doing regular sampling, and then
reversing the resulting samples.
The function can now sample to larger or smaller sample arrays:
- Larger output arrays have a point aligned with each source point as before,
with the rest of the points evenly distributed over the source curve.
This ensures that the output curve matches the source as closely as possible,
especially for poly curves.
- Smaller output arrays are uniformly sampled along the length of the source
curve.
Pull Request: https://projects.blender.org/blender/blender/pulls/141946
This commit moves the freestyle edge and face mark tags to become
generic attributes, similar to other changes over the past years. The
attributes are called "freestyle_edge" and "freestyle_face", and they're
now propagated like regular boolean attributes.
Compatibility wise, forward and backward blend file compatibility are
maintained (for forward compatibility this is implemented a bit
differently than in the past because of the ongoing `AttributeStorage`
transition). In the Python API, `use_freestyle_mark` has been removed;
the attribute API should be used instead (just like bevel weights).
The BMesh (`freestyle`) accessors are removed too.
The conversions benefit from the fact that bit-wise, the old structs are
the same as `bool`, so we can convert to the old and new formats without
reallocating arrays.
Pull Request: https://projects.blender.org/blender/blender/pulls/141996
Change `eCustomDataType` to `bke::AttrType` for uses of the attribute
API (the `AttributeAccessor` one anyway). I didn't touch any values that
might be saved in files; those should be handled on a case by case basis.
Part of #122398
Pull Request: https://projects.blender.org/blender/blender/pulls/141301
This commit moves Curves and Grease Pencil to use `AttributeStorage`
instead of `CustomData`, except for vertex groups. This PR mostly
involves extending the changes from the above commit for point clouds
to generalize to other geometry types.
This is mostly straightforward, though a couple non-trivial places of
note are the joining of Grease Pencil objects (`merge_attributes`), the
"default render fallback" UV for curves objects which was previously
unused at the UI level and just ended up being the first attribute, and
the `update_curve_types()` call in the curves versioning function.
Similar to:
- fa03c53d4a
- f74e304b00
Part of #122398.
Pull Request: https://projects.blender.org/blender/blender/pulls/140936
In a fix to manifold boolean, commit a20f367379, the code
sometimes dissolved vertices in triangles and then didn't remap
those vertices. This prevents the dissolve in the first place.