The split edges code had a complex method of merging duplicate edges,
going backwards to avoid shifting elements in a vector. Sometimes it
could result in incorrect corner edge indices though, if it moved an
index that matched one of the local variables (I think! I've bee
trying to understand this all day and still struggling). Instead,
replace it with a `VectorSet` that handles the deduplication by
itself, and avoid creating the new edges until the end.
I think this code could still be simpler if we tried to reduce the
amount of things happening at the same time, making more code
deal with the input or final state rather than an in-between one.
But to avoid making the change too complicated I stopped here.
Pull Request: https://projects.blender.org/blender/blender/pulls/108826
Fractal noise is the idea of evaluating the same noise function multiple times with
different input parameters on each layer and then mixing the results. The individual
layers are usually called octaves.
The number of layers is controlled with a "Detail" slider.
The "Lacunarity" input controls a factor by which each successive layer gets scaled.
The existing Noise node already supports fractal noise. Now the Voronoi Noise node
supports it as well. The node also has a new "Normalize" property that ensures that
the output values stay in a [0.0, 1.0] range. That is except for the F2 feature where
in rare cases the output may be outside that range even with "Normalize" turned on.
How the individual octaves are mixed depends on the feature and output socket:
- F1/Smooth F1/F2:
- Distance/Color output:
The individual Distance/Color octaves are first multiplied by a factor of
`Roughness ^ (#layers - 1.0)` then added together to create the final output.
- Position output:
Each Position octave gets linearly interpolated with the combined output of the
previous octaves. The Roughness input serves as an interpolation factor with
0.0 resutling in only using the combined output of the previous octaves and
1.0 resulting in only using the current highest octave.
- Distance to Edge:
- Distance output:
The Distance octaves are mixed exactly like the Position octaves for F1/Smooth F1/F2.
It should be noted that Voronoi Noise is a relatively slow noise function, especially
at higher dimensions. Increasing the "Detail" makes it even slower. Therefore, when
optimizing a scene one should consider trying to use simpler noise functions instead
of Voronoi if the final result is close enough.
Pull Request: https://projects.blender.org/blender/blender/pulls/106827
Add a quaternion attribute type that will be used in combination with
rotation sockets for geometry nodes to give a more intuitive experience
and better performance when using rotations.
The most interesting part is probably the interpolation, the rest is
the same as the last attribute type addition, 988f23cec3.
We need to interpolate multiple values with different weights.
Based on Sybren's suggestion, this uses the `expmap` methods from
4805a54525 for that.
This also refactors `SimpleMixerWithAccumulationType` to use a
function rather than a cast to convert to the accumulation type.
See #92967
Pull Request: https://projects.blender.org/blender/blender/pulls/108678
In some cases (when there are no faces for example, the offsets span
can have a size of 1 but no data). That's technically invalid and might
need to be addressed more later on, but for now, just fix the assert.
The quaternion header depended on the old C header where it doesn't
need to with a better alternative in the newer C++ types. Also remove an
unused function in another header.
During uv unwrapping and uv packing, certain floating point algorithms
have extreme sensitivity to round-off errors. These can produce very
different layouts even when given inputs which are only slightly different.
The root cause is that the two main types of CPUs used to run Blender,
namely x86 and Apple Silicon, produce slightly different results on some
math functions, including `sinf()`, `cosf()` and `atan2f()`.
* sinf(0.8960554599761962890625) = 0.780868828296661376953125 (Intel i7)
* sinf(0.8960554599761962890625) = 0.78086888790130615234375 (Apple M1)
This fix, and others that came before it [0], improve accuracy by using
double-precision to hide the differences between the CPUs.
[0] e.g. 0eba9e41bf
[1] See also #107829
This includes square root and reciprocal, and their safe versions.
For the reciprocal use name rcp, which matches Cycles and allows
to implement the same function for per-element operation on matrices.
Pull Request: https://projects.blender.org/blender/blender/pulls/108705
Returning the pointer to the null byte when the character isn't found
is useful when handling null terminated strings that contain newlines.
This means the return value is never null and the line span always ends
at the resulting value.
When the loose edge and vertex status are cached in the source mesh and
the combination of selection domain and mode don't add loose elements,
copy the cache status to avoid recomputation. In a test with a 1 million
face grid:
- All: 23 -> 30 FPS
- Only faces: 22 -> 23.5 FPS
- Only edges and faces: 24 -> 27 FPS
Also remove unnecessary includes and fix a build error introduced in
the last commit to this area from an inconsistent forward declaration.
Replace the implementation of the separate and delete geometry nodes
for meshes. The new code makes more use of the `IndexMask` class, which
was recently optimized. The main goal is to make more of the work scale
with the size of the result mesh rather than the input. For example,
instead of keeping a map from input to output elements, the maps used
to copy attributes go from output to input elements.
The new implementation is generally 2-4x faster, depending on the mode
and the number of elements selected. The new code is also able to skip
more work when nothing is removed.
This also allows using more existing attribute interpolation code,
allowing the overall removal of over 300 lines. Some of the attribute
utilities from a similar change for curves (f63cfd8e28) are
reused directly.
The indices of the result changes, so the test file needs to be updated.
Pull Request: https://projects.blender.org/blender/blender/pulls/108435
IndexMask::complement() is often used in geometry processing
algorithms when a selection needs to be inverted, mostly just in
curves code so far.
Instead of reusing `from_predicate` and lookup in the source mask,
scan the mask once, inserting segments between the original indices.
Theoretically this improves the performance from O(N*log(N)) to O(N).
But with the small constant offset of the former, the improvement is
generally just 3-4 times faster. However in some cases like empty
and full masks, the new code takes constant time.
![image](/attachments/d2f6b0be-f195-4206-9bf4-c0ab20041d1b)
Pull Request: https://projects.blender.org/blender/blender/pulls/108331
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.
This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.
Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.
Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:
https://reuse.software/faq/
Avoid BLI_path_slash_rfind for accessing file-names as NULL is returned
when the path has no slashes, use BLI_path_basename instead.
Also remove 2 cases where BLI_path_basename was inlined.
When the new name was clipped to make room for the number,
the string was clipped by the number size (including the null byte).
Store the length in `numlen` instead of the size (including null byte).
The mask was sliced, but the original mask was used from before the
slicing, causing an unsliced mask to be used with the new offsets.
This caused a crash in the hair styles demo file.
Windows file associations using ProgID, needed because of the launcher.
This fixes "pin to taskbar" and Recent Documents lists, allow per-
version jump lists and an "Open with" list with multiple versions.
Pull Request: https://projects.blender.org/blender/blender/pulls/107013
Goals of this refactor:
* Reduce memory consumption of `IndexMask`. The old `IndexMask` uses an
`int64_t` for each index which is more than necessary in pretty much all
practical cases currently. Using `int32_t` might still become limiting
in the future in case we use this to index e.g. byte buffers larger than
a few gigabytes. We also don't want to template `IndexMask`, because
that would cause a split in the "ecosystem", or everything would have to
be implemented twice or templated.
* Allow for more multi-threading. The old `IndexMask` contains a single
array. This is generally good but has the problem that it is hard to fill
from multiple-threads when the final size is not known from the beginning.
This is commonly the case when e.g. converting an array of bool to an
index mask. Currently, this kind of code only runs on a single thread.
* Allow for efficient set operations like join, intersect and difference.
It should be possible to multi-thread those operations.
* It should be possible to iterate over an `IndexMask` very efficiently.
The most important part of that is to avoid all memory access when iterating
over continuous ranges. For some core nodes (e.g. math nodes), we generate
optimized code for the cases of irregular index masks and simple index ranges.
To achieve these goals, a few compromises had to made:
* Slicing of the mask (at specific indices) and random element access is
`O(log #indices)` now, but with a low constant factor. It should be possible
to split a mask into n approximately equally sized parts in `O(n)` though,
making the time per split `O(1)`.
* Using range-based for loops does not work well when iterating over a nested
data structure like the new `IndexMask`. Therefor, `foreach_*` functions with
callbacks have to be used. To avoid extra code complexity at the call site,
the `foreach_*` methods support multi-threading out of the box.
The new data structure splits an `IndexMask` into an arbitrary number of ordered
`IndexMaskSegment`. Each segment can contain at most `2^14 = 16384` indices. The
indices within a segment are stored as `int16_t`. Each segment has an additional
`int64_t` offset which allows storing arbitrary `int64_t` indices. This approach
has the main benefits that segments can be processed/constructed individually on
multiple threads without a serial bottleneck. Also it reduces the memory
requirements significantly.
For more details see comments in `BLI_index_mask.hh`.
I did a few tests to verify that the data structure generally improves
performance and does not cause regressions:
* Our field evaluation benchmarks take about as much as before. This is to be
expected because we already made sure that e.g. add node evaluation is
vectorized. The important thing here is to check that changes to the way we
iterate over the indices still allows for auto-vectorization.
* Memory usage by a mask is about 1/4 of what it was before in the average case.
That's mainly caused by the switch from `int64_t` to `int16_t` for indices.
In the worst case, the memory requirements can be larger when there are many
indices that are very far away. However, when they are far away from each other,
that indicates that there aren't many indices in total. In common cases, memory
usage can be way lower than 1/4 of before, because sub-ranges use static memory.
* For some more specific numbers I benchmarked `IndexMask::from_bools` in
`index_mask_from_selection` on 10.000.000 elements at various probabilities for
`true` at every index:
```
Probability Old New
0 4.6 ms 0.8 ms
0.001 5.1 ms 1.3 ms
0.2 8.4 ms 1.8 ms
0.5 15.3 ms 3.0 ms
0.8 20.1 ms 3.0 ms
0.999 25.1 ms 1.7 ms
1 13.5 ms 1.1 ms
```
Pull Request: https://projects.blender.org/blender/blender/pulls/104629
Combine the newer less efficient C++ implementations and the older
less convenient C functions. The maps now contain one large array of
indices, split into groups by a separate array of offset indices.
Though performance of creating the maps is relatively unchanged, the
new implementation uses 4 bytes less per source element than the C
maps, and 20 bytes less than the newer C++ functions (which also
had more overhead with larger N-gons). The usage syntax is simpler
than the C functions as well.
The reduced memory usage is helpful for when these maps are cached
in the near future. It will also allow sharing the offsets between
maps for different domains like vertex to corner and vertex to face.
A simple `GroupedSpan` class is introduced to make accessing the
topology maps much simpler. It combines offset indices and a separate
span, splitting it into chunks in an efficient way.
Pull Request: https://projects.blender.org/blender/blender/pulls/107861
Covers the macro ARRAY_SIZE() and STRNCPY.
The problem this change is aimed to solve it to provide cross-platform
compiler-independent safe way pf ensuring that the functions are used
correctly.
The type safety was only ensured for GCC and only for C. The C++
language and Clang compiler would not have detected issues of passing
bare pointer to neither of those macros.
Now the STRNCPY() will only accept a bounded array as the destination
argument, on any compiler.
The ARRAY_SIZE as well, but there are a bit more complications to it
in terms of transparency of the change.
In one place the ARRAY_SIZE was used on float3 type. This worked in the
old code because the type implements subscript operator, and the type
consists of 3 floats. One would argue this is somewhat hidden/implicit
behavior, which better be avoided. So an in-lined value of 3 is used now
there.
Another place is the ARRAY_SIZE used to define a bounded array of the
size which matches bounded array which is a member of a struct. While
the ARRAY_SIZE provides proper size in this case, the compiler does not
believe that the value is known at compile time and errors out with a
message that construction of variable-size arrays is not supported.
Solved by converting the field to std::array<> and adding dedicated
utility to get size of std::array at compile time. There might be a
better way of achieving the same result, or maybe the approach is
fine and just need to find a better place for such utility.
Surely, more macro from the BLI_string.h can be covered with the C++
inlined functions, but need to start somewhere.
There are also quite some changes to ensure the C linkage is not
enforced by code which includes the headers.
Pull Request: https://projects.blender.org/blender/blender/pulls/108041
This is necessary for correctness of the code to avoid duplicate symbols.
In practice, this wasn't necessary yet, because usually we pass lambdas
into these functions which cause every instantiation to have a different
signature.
Alignment here means that the size of the range passed into callback
is a multiple of the alignment value (which has to be a power of two).
This can help with performance when loops in the callback are are
unrolled and/or vectorized. Otherwise, it can potentially reduce
performance by splitting work into more unequally sized chunks.
For example, chunk sizes might be 4 and 8 instead of 6 and 6 when
alignment is 4.
This is useful when debugging how much memory a particular function
allocates from this allocator. The change also reduces the size of
`LinearAllocator`.
Defining `operator-` for the iterator allows it to be used in more generic
iterator code. The `index_range` method is the same that exists on many
other containers like `Vector`.
Previously, `tbb::parallel_for` was instantiated every time `threading::parallel_for`
is used. However, when actual parallelism is used, the overhead of a function
call is negilible. Therefor it is possible to move that part out of the header
without causing noticable performance regressions.
This reduces the size of the Blender binary from 308.2 to 303.5 MB, which is
a reduction of about 1.5%.
This function handles cleaning valid system paths that are functional
when passed to `open(..)` but may be relative to the current working
directory or have redundant slashers that can be normalized.
- Add BLI_path_slash_ensure_ex which takes the string length.
- Normalize functions now return the string length,
so ensuring trailing a trailing slash is a simple check.
This would have avoided the off-by-one error from
761eac2f5d.
Add modulo function `mod_f_positive(f, n)` that returns a positive result,
regardless of the sign of `f`.
For example, `mod_f_positive(-0.1, 1.0)` returns `0.9`, whereas the
standard `fmodf()` function would return `-0.1`.
This is useful for rewrapping values to a specific interval.
Include the term "overwrite" so users of this function are aware
this function will delete the destination file (unlike LIBC rename).
- Add BLI_rename_overwrite (previously called BLI_rename).
- BLI_rename is now a wrapper for rename.
Use BLI_rename when renaming in the file selector.
This change was made to prevent renaming files in the file selector from
deleting the file, see: #12255 & [0]. This check is no longer needed as
file selectors now checks the destination doesn't exist before renaming.
Generally, having low level file handling functions behave differently
between platforms is something to avoid with the potential of leading
to unexpected behavior.
Also unify WIN32/UNIX BLI_rename.
[0]: 41ad6f9d0a
When the `from` file didn't exist, BLI_rename returned success,
the in-line doc-string was incorrect - remove in favor of the header's
doc-string. This error existed since the initial revision.
Note that this was fixed [0] for other systems.
[0]: 622019a085
Ensure the file path G.main->filepath is always absolute and normalized.
- It was possible to call WM_OT_open_mainfile with only a filename,
if this resolved from the CWD, Blender's internal filepath
would not be absolute as expected.
- It was possible to open files on UNIX with an additional forward slash
causing the blend file path it's self to contain a '//' prefix,
this is error prone as running BLI_path_abs(..) multiple times would
add the blend file prefix each time.
- Remove requirement for "filepath" to be an absolute path when saving.
Instead, expand the path - making it absolute, as this constraint
wasn't applied open opening files, prefer making save/open behave
consistently.
- Assert when BLI_path_abs/BLI_path_rel receive a basepath that has
a "//" (relative) prefix itself.
Double-clicking between alpha-numeric & punctuation for e.g.
did nothing instead of selecting the word.
Instead of a special check for white-space, use the enum values as a
priority so alpha-numeric characters are priories above others
in a way that doesn't prevent groups of other character types
from being selected.
Having some arguments be input/output and others output only was
confusing, a function that detects a range from a position
can simply calculate the range - modifying the input position isn't
needed.
Instead, note that word select puts the cursor at the end by convention.
Also use `r_` prefix for output only arguments.
These are now the only two BLI_path functions which assume paths are
FILE_MAX size which makes sense as they're using the `//` file prefix.
Something that's specific to file paths stored in DNA.
Use FILE_MAX in the function signature as a form of documentation.
Add a convenient way to replace a range of text in the middle of a
string that make shrink or grow the string that handles corner cases
and keeps the string null terminated.
There was even one case in BLI ListBase tests!
Order was opposite of the one expected by the BLI ListBase code... Not
sure how, but this did not cause any issue apparently? But would expect
it to at least affect the order in which items in the list would be
iterated.
Due to cumulative floating point errors the quaternions produced by
`mat3_normalized_to_quat_fast()` could be non-unit length. This is now
detected, and quaternions are normalised when necessary.
This is a slight roll-back of 756538b4a1,
which removed the normalisation altogether, but did introduce this issue.
Vulkan doesn't have a conversion from uint32_t/int32_t to float. It does
have conversions from 16/8 bits. Main reason is that Vulkan expects that
there is no benefit when converting 32 bits from one type to the other
and should be solved by passing the right data type.
In Blender however this isn't the case as there are benefits on other
GPU backends (OpenGL for example).
This PR adds helper function to check if conversion is needed and
perform any conversions in place. It also implements the function to
upload vertex buffers to the GPU.
NOTE: Test cases have been added to validate this, but they are not
able to run on the Vulkan backend just yet, because they require the
graphics pipeline to be available.
Pull Request: https://projects.blender.org/blender/blender/pulls/107733
BLI_strncpy_utf8 didn't check for null bytes within bytes stepped
over by the variable length UTF8 encoding.
While a valid UTF8 string wont include these, it's possible Latin1
encoding or a truncated string includes such characters.
In this case, the entire string is copied as it's not the purpose of
this function to correct or strip invalid/truncated encoding,
only to prevent it from happening in the first place.
Avoid instantiating the templates separately in every translation unit.
This saves 20 KB in my Blender binary. Also remove a timer mistakenly
committed.
Replace MAXPATHLEN with FILE_MAX, always allocate if the buffer isn't
big enough since creating a truncated directory isn't useful.
Having some code-paths only run in an ifdef complicated the code
and made it more difficult to follow.
Also assert the path doesn't contain ".." directories as they aren't
supported.
- Don't duplicate/allocate the path on each recursion,
instead make a single copy which is modified in-place.
- Move slash-stepping to a BLI_path utility function that accesses
the end position of the parent directory, handles multiple slashes
and '/./'.
Only use the term len & maxlen when they represent the length & maximum
length of a string. Instead of the available bytes to use.
Also include the data they're referencing as a suffix, otherwise it's
not always clear what the length is in reference to.
Reserve the term `len` for string length, some functions used this for
an string/array length, others a destination buffer size
(even within a single function declaration).
Also improve naming consistency across different functions.
`sinf(float_angle)` is sometimes producing different results on
x86_64 cpus and apple silicon cpus. Convert to double precision
to increase accuracy and consistency.
Partial fix for #104513. More to come.
There is no advantage in using BLI_strncpy/BLI_strncpy_utf8 when the
destination string has been allocated and won't be concatenated.
Also no need to calloc memory which is filled by strcpy afterwards.
- Names ending with len sometimes referred to the buffer size.
The same names were used for both buffer size and string length
depending on the function in some cases.
- Rename str/string to path for generic path functions.
- Rename BLI_path_rel arguments (file, relfile) to (path, basename)
as it wasn't so clear which is being made relative, `file` can be a
directory so rename to `path` (matches naming for BLI_path_abs).
- Avoid inline ifdef checks for DEBUG_STRSIZE
- Add BLI_string_debug_size_after_nil to ensure strings to manipulate
have the expected buffer size after the nil terminator.
- Add checks to more string manipulation functions.
Further changes are required for this to be enabled during regular
development as the RNA currently allocates the strings length but
passes in the buffer size as a limit which conflicts with DEBUG_STRSIZE.
This adds support for building simulations with geometry nodes. A new
`Simulation Input` and `Simulation Output` node allow maintaining a
simulation state across multiple frames. Together these two nodes form
a `simulation zone` which contains all the nodes that update the simulation
state from one frame to the next.
A new simulation zone can be added via the menu
(`Simulation > Simulation Zone`) or with the node add search.
The simulation state contains a geometry by default. However, it is possible
to add multiple geometry sockets as well as other socket types. Currently,
field inputs are evaluated and stored for the preceding geometry socket in
the order that the sockets are shown. Simulation state items can be added
by linking one of the empty sockets to something else. In the sidebar, there
is a new panel that allows adding, removing and reordering these sockets.
The simulation nodes behave as follows:
* On the first frame, the inputs of the `Simulation Input` node are evaluated
to initialize the simulation state. In later frames these sockets are not
evaluated anymore. The `Delta Time` at the first frame is zero, but the
simulation zone is still evaluated.
* On every next frame, the `Simulation Input` node outputs the simulation
state of the previous frame. Nodes in the simulation zone can edit that
data in arbitrary ways, also taking into account the `Delta Time`. The new
simulation state has to be passed to the `Simulation Output` node where it
is cached and forwarded.
* On a frame that is already cached or baked, the nodes in the simulation
zone are not evaluated, because the `Simulation Output` node can return
the previously cached data directly.
It is not allowed to connect sockets from inside the simulation zone to the
outside without going through the `Simulation Output` node. This is a necessary
restriction to make caching and sub-frame interpolation work. Links can go into
the simulation zone without problems though.
Anonymous attributes are not propagated by the simulation nodes unless they
are explicitly stored in the simulation state. This is unfortunate, but
currently there is no practical and reliable alternative. The core problem
is detecting which anonymous attributes will be required for the simulation
and afterwards. While we can detect this for the current evaluation, we can't
look into the future in time to see what data will be necessary. We intend to
make it easier to explicitly pass data through a simulation in the future,
even if the simulation is in a nested node group.
There is a new `Simulation Nodes` panel in the physics tab in the properties
editor. It allows baking all simulation zones on the selected objects. The
baking options are intentially kept at a minimum for this MVP. More features
for simulation baking as well as baking in general can be expected to be added
separately.
All baked data is stored on disk in a folder next to the .blend file. #106937
describes how baking is implemented in more detail. Volumes can not be baked
yet and materials are lost during baking for now. Packing the baked data into
the .blend file is not yet supported.
The timeline indicates which frames are currently cached, baked or cached but
invalidated by user-changes.
Simulation input and output nodes are internally linked together by their
`bNode.identifier` which stays the same even if the node name changes. They
are generally added and removed together. However, there are still cases where
"dangling" simulation nodes can be created currently. Those generally don't
cause harm, but would be nice to avoid this in more cases in the future.
Co-authored-by: Hans Goudey <h.goudey@me.com>
Co-authored-by: Lukas Tönne <lukas@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/104924
- Rename name/filename/path to filepath when it's used for full paths.
- Rename name/path to dirpath when it refers to a directory.
- Rename file to filepath or path (when it may be a file or dir).
- Rename ImBuf::name & anim::name to filepath.
Rename BLI_make_existing_file to BLI_file_ensure_parent_dir_exists.
The previous name read as if it would make (touch) the file,
where as it ensures the directory component of the path exists.
Move from BLI_path to BLI_fileops as path utilities should only
manipulate paths and not deal with file IO creation
(this has more in common with BLI_file_touch for e.g.).
A NULL defname would early exit (doing nothing) this isn't good behavior
as this function should always make the name unique and a NULL defname
is likely an error in the code which would allow duplicate names.
This is also inconsistent with BLI_uniquename_cb which always
wrote the defname into the name if it was empty.
Mark this argument as never-NULL.
Explicitly list ATTR_NONNULL indices in most cases so it's explicit
that arguments aren't NULL (and adding new arguments that can be NULL
isn't such a hassle).
This fixes a crash where merging vertices by distance leads to a crash since
0652945dbd. The change did not cause
the bug though, it just made the underlying issue visible.
The issue was that `kdtree_order` assumed that the `KDTreeNode.index` didn't
have gaps, i.e. every index in a certain range is used. However, that is not the
case when only a subset of the vertices of a mesh are added to the kdtree.
Pull Request: https://projects.blender.org/blender/blender/pulls/107535