Compare commits

...

166 Commits

Author SHA1 Message Date
0e4a04a07f Remove debug code. 2022-05-13 12:57:53 +02:00
c4b20425bd Improve quality seam fixing (step distance) 2022-05-13 12:38:23 +02:00
f39e871490 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-05-13 09:43:58 +02:00
c8f3ec797c Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-05-11 10:35:58 +02:00
2e046183a2 Use source blending with a mask. 2022-05-04 18:47:30 +02:00
654e242d43 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-05-04 15:08:44 +02:00
9ce9cf5a31 Make seamfix distance as a user controlled setting per image. 2022-05-02 14:33:52 +02:00
e80c6c48aa Add early exits to skip bitmaps. 2022-05-02 13:34:42 +02:00
34ff126470 Renamed watertight to image_tile_user. 2022-05-02 13:30:25 +02:00
4ce7dab4c6 Fix some artifacts by checking the winding order. 2022-05-02 13:28:59 +02:00
cd277c94e7 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-05-02 12:25:59 +02:00
f7c0638258 Separate projection code. 2022-05-02 10:53:47 +02:00
0e5a73fe8a Remove limit check in uv space. 2022-05-02 09:27:50 +02:00
87ea1d1d63 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-05-02 09:00:02 +02:00
9cbfcc7f3c Remove fixd todo. 2022-04-22 16:04:47 +02:00
0bd2f9dcff Revert workbench change. 2022-04-22 16:04:34 +02:00
d96172376d UDIM support. 2022-04-22 16:01:13 +02:00
f43a9e6c65 Use constant for distance. 2022-04-22 14:29:31 +02:00
ca4de164a5 Rename ldata_uvs to ldata_uv 2022-04-22 14:00:52 +02:00
7b4bc72a49 Remove BMesh. 2022-04-22 13:51:45 +02:00
ab26e4d6a7 Better Seam fix detection 2022-04-22 10:49:45 +02:00
44126f76ea Determine region to update from changed pixels. 2022-04-22 09:45:12 +02:00
cfed819761 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-04-22 08:35:28 +02:00
Jung Jaeyun
7c1556a497 UI: Add option to create color attribute directly from canvas selector.
Added + and - buttons to create and delete color attributes from canvas selector.

{T97345}

{F13006374}

Reviewed By: jbakker, Ethan1080

Maniphest Tasks: T97345

Differential Revision: https://developer.blender.org/D14672
2022-04-22 08:28:52 +02:00
2decd837f6 Build: updates for Blender to build against new 3.2 libraries
Building against the existing 3.1 libraries should continue to work, until
the precompiled libraries are committed for all platforms.

* Enable WebP by default.
* Update Windows for new library file names.
* Automatically clear outdated CMake cache variables when upgrading to new
  libraries.
* Fix static library linking order issues on Linux for OpenEXR and OpenVDB.

Implemented by Ray Molenkamp, Sybren Stüvel and Brecht Van Lommel.

Ref T95206
2022-04-22 08:28:52 +02:00
fb66386beb Build: upgrade many library dependencies to new versions for Blender 3.2
This only updates the build system, precompiled libraries for the various
platforms will be committed over the coming week.

New:
fmt 8.0.0
level_zero v1.7.15
pystring v1.1.3
robinmap v0.6.2
webp 1.2.2

Updated:
alembic 1.8.3
blosc 1.21.1
boost 1.78.0
embree 3.13.3
ffmpeg 5.0
fftw 3.3.10
flac 1.3.4
imath 3.1.4
ispc v1.17.0
jpeg 2.1.3
ogg 1.3.5
oidn 1.4.3
openal 1.21.1
opencolorio 2.1.1
openexr 3.1.4
openimageio v2.3.13.0
openjpeg 2.4.0
opensubdiv v3_4_4
openvdb 9.0.0
osl 1.11.17.0
sdl 2.0.20
tbb 2020_u3
tiff 4.3.0
usd 22.03
vorbis 1.3.7
vpx 1.11.0
x264 35fe20d1b
zlib 1.2.12

Implemented by Ray Molenkamp, Sybren Stüvel and Brecht Van Lommel.

Ref T95206
2022-04-22 08:28:52 +02:00
e0a1299aee Cleanup: Remove redundant types from custom data masks
Colors and byte colors are already included in `CD_MASK_PROP_ALL`.
2022-04-22 08:28:52 +02:00
7cc51a464c Cleanup: Rename CD_MLOOPCOL to CD_PROP_BYTE_COLOR
The "PROP" in the name reflects its generic status, and removing
"LOOP" makes sense because it is no longer associated with just
mesh face corners. In general the goal is to remove extra semantic
meaning from the custom data types.
2022-04-22 08:28:52 +02:00
245fb6472c Use partial updates. 2022-04-20 14:35:45 +02:00
3a2fb294b8 Move detemination of cd offset closer to where it is used. 2022-04-20 13:52:26 +02:00
b577f11a5e Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-04-20 13:47:05 +02:00
998d541568 connected edges. 2022-04-20 13:23:47 +02:00
c89e73209a Fix crash painting on byte textures. 2022-04-20 10:42:59 +02:00
86d9ec6df7 Make connected fixes with more priority. 2022-04-20 10:38:14 +02:00
4b281ecd74 Fix unconnected seams. 2022-04-20 09:20:47 +02:00
5c5d5b27a0 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-04-20 07:46:25 +02:00
ab8c980365 Seam extraction. 2022-04-19 16:00:50 +02:00
11bcb614b5 Seam building. 2022-04-19 12:25:24 +02:00
77e47b7e01 Merge branch 'master' into temp-T97352-3d-texturing-seam-bleeding 2022-04-19 11:02:37 +02:00
aef482b72f Fix: Uninitialized paint brush when using byte textures.
This is a fix for the 3d texturing brush.
2022-04-19 08:35:54 +02:00
0e4ec7d9d3 Seam bleeding. 2022-04-15 16:31:14 +02:00
9852c6cf63 Only store 2 components of barycentric coordinates. 2022-04-15 12:00:02 +02:00
c627d7ede2 Remove experimental uv seam bleeding 2022-04-15 11:51:21 +02:00
1f8e9ad6de Color management of brush colors 2022-04-15 09:24:28 +02:00
5ba160ce96 Removed lock attribute from ImageData struct. 2022-04-15 08:38:56 +02:00
9daf4a8040 Move brush_test from triangles to do_paint_pixels. 2022-04-15 08:08:41 +02:00
f6bac97d16 Removed bad import. 2022-04-15 07:59:41 +02:00
ae13c11a95 Fix painting on UDIM tiles. 2022-04-13 15:44:15 +02:00
c6da2a827f Merge branch 'master' into temp-T96710-pbvh-pixels 2022-04-13 14:45:56 +02:00
211ba8df0b Remove unused include statement. 2022-04-13 13:42:55 +02:00
248339a1cb Reverted file spece_view3d.c 2022-04-13 13:41:16 +02:00
ae027413f4 Rebuild pixels when image resolution/uvmap changes. 2022-04-13 13:37:16 +02:00
9b16782aef Remove msg bus subscribe. 2022-04-13 11:06:21 +02:00
83d4cf9db1 PBVH: triangle brush test. 2022-04-13 10:53:18 +02:00
809501289d Remove vertex based brush testing. 2022-04-12 15:25:59 +02:00
d3918312d8 Added support for secondary brush color. 2022-04-12 14:27:50 +02:00
01f79f7c93 Remove using namespace. 2022-04-12 14:02:27 +02:00
ea486bcd3d Remove indices from Triangles. Index of the triangle is in sync with prim list. 2022-04-12 13:59:39 +02:00
1ec0129cfa Fix quad data stored multiple times. 2022-04-12 13:35:16 +02:00
cf8b29950b Don't call a function to update the node state. 2022-04-12 12:10:11 +02:00
66b03b7e3b Change the tile painting loop to use node data first. 2022-04-12 12:07:37 +02:00
0947875637 Remove image locking. 2022-04-12 11:45:36 +02:00
798db23477 Renamed inner type to ImageBuffer. 2022-04-12 11:35:01 +02:00
21caf27fa9 Remove Pixel class. 2022-04-12 11:22:00 +02:00
b7e511373a Use primitives stored in PBVH. 2022-04-12 11:10:45 +02:00
f49adba9c1 Removed doxygen comments. 2022-04-12 10:43:24 +02:00
7c181c8982 Removed VisitedPolygons. 2022-04-12 10:41:43 +02:00
b57ea0330c Remve extractor namespace. 2022-04-12 10:37:40 +02:00
167da68133 Remove unused code. 2022-04-12 10:35:01 +02:00
701c225675 Encapsulate clear_dirty/mark_dirty. 2022-04-12 10:28:47 +02:00
9112d13e69 Rename TIleData to UDIMTilePixels 2022-04-12 09:53:20 +02:00
9a0180e3e7 Rename PixelsPackage to PackedPixelRow. 2022-04-12 09:49:32 +02:00
10509846db Remove Triangle struct. 2022-04-12 08:42:16 +02:00
ca7d7e02c3 Spelling in comments. 2022-04-12 08:30:17 +02:00
67e831af28 Remove BarycentricWeights. 2022-04-12 08:26:24 +02:00
386f0e47e4 Renamed BKE_pbvh.hh BKE_pbvh_pixels.hh. 2022-04-12 08:16:33 +02:00
83dbe62e71 Renamed PBVH_UpdatePixels to PBVH_RebuildPixels. 2022-04-12 08:12:24 +02:00
b1b5113b99 Fix Windows build error. 2022-04-11 15:57:49 +02:00
5442e0720f Add image user for painting on single image. 2022-04-11 15:48:51 +02:00
4498e0ea6b Small cleanup in code and comments. 2022-04-11 14:45:25 +02:00
7b4103eed1 Attached canvas selection to texture painting. 2022-04-11 14:15:54 +02:00
73e0b48e41 Merge remote-tracking branch 'origin/master' into temp-T96710-pbvh-pixels 2022-04-11 11:44:44 +02:00
4d2a4f8582 Silenced compilation warning CLANG. 2022-04-11 11:31:35 +02:00
af1f0e166d Correct region tagging. 2022-04-11 11:19:35 +02:00
6469dcfe41 Added timings around update. 2022-04-11 09:40:07 +02:00
da5662cd0f Remove sorting and barycentric encoding. 2022-04-11 09:07:04 +02:00
4fcf554088 Silence compilation warning. 2022-04-11 08:26:45 +02:00
9863f5359f Disable pixel package sorting. 2022-04-08 16:34:14 +02:00
5b7ed8bea0 Merge branch 'temp-T96710-pbvh-pixels' of git.blender.org:blender into temp-T96710-pbvh-pixels 2022-04-08 15:47:21 +02:00
2cd6dfc44f Merge branch 'master' into temp-T96710-pbvh-pixels 2022-04-08 15:43:36 +02:00
f79da200c5 UV Seam extraction.
Differential Revision: https://developer.blender.org/D14599
2022-04-08 15:40:42 +02:00
220b10a689 Use context to pass common parameters. 2022-04-08 15:21:13 +02:00
ab6c400d14 Extending using line segment intersection. 2022-04-08 14:53:12 +02:00
5c25182aff Seams extension in x. 2022-04-08 12:52:49 +02:00
bfb9faaded Extend seams in x direction. 2022-04-08 11:07:41 +02:00
3bf7f06a26 PyAPI: use keyword only arguments for Text.region_{from/to} string
This is the convention for most parts of Blender Python API.
2022-04-08 11:07:41 +02:00
067ffe96a4 Cleanup: separate format-units for Python argument parsing
With the increased use of multi-character format units and keyword-only
arguments these are increasingly difficult to make sense of.

Split the string onto multiple lines, one per argument.
While verbose it's easier to understand and add new arguments.
2022-04-08 11:07:41 +02:00
cf9f997d80 Cleanup: Define new curves normal mode in DNA
Don't include the tangent mode for now, since that
was never implemented for geometry nodes curves.
2022-04-08 11:07:41 +02:00
64f1c223f9 Cycles: Support adding Lightgroups from the object/world properties
Currently, only Lightgroups that exist in the current view layer can be
selected from object or world properties.

The internal UI code already has support for search fields that accept
unknown input, so I just added that to the API and use it for lightgroups.

When a lightgroup is entered that does not exist in the current view layer
(e.g. because it's completely new, because the view layer was switched or
because it was deleted earlier), a new button next to it becomes active and
adds it to the view layer when pressed.

Differential Revision: https://developer.blender.org/D14540
2022-04-08 11:07:41 +02:00
84df064cfa Fix T97144 Overlay: Illegal recursive expansion of macros
Was caused by the shaderCreateInfo port.
2022-04-08 11:07:41 +02:00
66c4eee016 Fix Clang/Linux build error after line primitive parallelization 2022-04-08 11:07:41 +02:00
c8b78bfa8e Fix Cycles build error after recent changes 2022-04-08 11:07:41 +02:00
175dfbb708 Cycles: various Linux build fixes related to Hydra render delegate
* Add missing GLEW and hgiGL libraries for Hydra
* Fix wrong case sensitive include
* Fix link errors by adding external libs to static Hydra lib
* Work around weird Hydra link error with MAX_SAMPLES
* Use Embree by default for Hydra
* Sync external libs code with standalone
* Update version number to match Blender
* Remove unneeded CLEW/GLEW from test executable

None of this should affect Cycles in Blender.

Ref T96731
2022-04-08 11:07:41 +02:00
8acf269817 Cleanup: remove unused mface tesselation code from modifier stack
This seems to serve no purpose anymore, I don't see anywhere that
CD_MFACE is requested for modifier evaluation, and it's confusing
to have this in this final normals computation function.

Found while looking into D14579.

Differential Revision: https://developer.blender.org/D14580
2022-04-08 11:07:41 +02:00
0867c2401b Fix T97035: crash transferring face corner data
The mechanism to instance meshes when there are no modifiers did not take
into account that modifiers might get re-evaluated from an operator that
requests loop normals. Now check for that case and no longer use the
instance then.

In the future, a better solution may be to compute loop normals on demand
as is already done for poly and vertex normals, but that would be a big
change.

Differential Revision: https://developer.blender.org/D14579
2022-04-08 11:07:41 +02:00
e5a8128575 Cleanup: Return early in metaball tessellation code
Also declare variables where initialized and use const.
2022-04-08 11:07:40 +02:00
81669eeb0c BLI: inline fast path of IndexRange::as_span
This frequently showed up in profiling but shouldn't.

This also updates the code to use atomics for more correctness and
adds multi-threading for better performance.
2022-04-08 11:07:40 +02:00
3f4c47e96e Functions: optimize simple generated multi-functions
This implements two optimizations:
* Reduce virtual function call overhead when a non-standard virtual
  array is used as input.
* Use a lambda in `type_conversion.cc`.

In my test setup, which creates a float attribute filled with the index,
the running time drops from `4.0 ms` to `2.0 ms`.

Differential Revision: https://developer.blender.org/D14585
2022-04-08 11:07:40 +02:00
04cd5303fb Geometry Nodes: Parallelize mesh line node
I observed a 4-5x performance improvement (from 50ms to 12ms)
with five million points, though obviously the change depends on
the hardware.

In the future we may want to disable the parallelization in
`parallel_invoke` when there is a small amount of points.

Differential Revision: https://developer.blender.org/D14590
2022-04-08 11:07:40 +02:00
Henrik Dick
1be8a1260c GPencil: Add skip option to envelope modifier
This patch adds an option to only use every n-th segment of the
envelope result. This can be used to reduce the complexity of the
result.

Differential Revision: http://developer.blender.org/D14503
2022-04-08 11:07:40 +02:00
28d1c86b49 Cleanup: Compilation warning about virtual functions
Method which overrides a base class's virtual methods are expetced to
be marked with `override`. This also gives better idea to the developers
about what is going on.
2022-04-08 11:07:40 +02:00
520e80d9cc Fix T97123: Applying modifier to multi-user: other objects were also converted
The first element of the iterator was not being tested against the flag.
So in some cases it would lead to more objects been made into
single-user than the active (or selected) ones.
2022-04-08 11:07:40 +02:00
82c2e61fbd Cleanup: add clarifying comment to bpy_app_getsets
No functional changes.
2022-04-08 11:07:40 +02:00
cd11b92f2d Curves: improve Add menu for new curves object
The goal is to make the Add menu more convenient for the new curves object.
The following changes are done:
* Add `curves` submenu.
* Add an `Empty Hair` operator that also sets the surface object.
* Rename the old operator to `Random`. It's mostly for testing at this point.

Differential Revision: https://developer.blender.org/D14556
2022-04-08 11:07:40 +02:00
bf066f9393 Curves: operator to snap curves to surface
This operator snaps the first point of every curve to the corresponding
surface object. The shape of individual curves or their orientation is
not changed.

There are two different attachment modes:
* `Nearest`: Move each curve so that the first point is on the closest
  point on the surface. This should be used when the topology of the
  surface mesh changed, but the shape generally stayed the same.
* `Deform`: Use the existing attachment information that is stored
  for curves to move curves to their new location when the surface
  mesh was deformed. This generally does not work when the
  topology changed.

The purpose of the operator is to help setup the "ground truth"
for how curves are attached to the surface. When the ground
truth surface changed, the original curves have to be updated
as well. Deforming curves based on an animated surface will be
done with geometry nodes independent of the operator.

In the UI, the operator is currently exposed in curves sculpt mode
in the `Curves > Snap Curves to Surface` menu.

Differential Revision: https://developer.blender.org/D14515
2022-04-08 11:07:40 +02:00
fc461c1c25 Cleanup: make CustomMF_* implementations more similar 2022-04-08 11:07:40 +02:00
e0abad2f6a Pose Library: avoid errors in the legacy panel when the add-on is disabled
Avoid errors in the legacy Pose Library panel (in Armature properties)
when the Pose Library add-on is disabled.

It's unfortunate that a built-in panel now has knowledge of an add-on.
Then again, it's temporary (one or two Blender releases), and it now uses
feature detection instead of just assuming the add-on is enabled.
2022-04-08 11:07:40 +02:00
9088eac81b Pose Library: use the right icon for the "More Info" button 2022-04-08 11:07:40 +02:00
1fc4efd966 Cleanup: remove incorrect comment
No functional changes.
2022-04-08 11:07:40 +02:00
16aed16ec0 Fix T96888: data transfer operator crash in certain situation
The operator could crash in case the context "object" was overridden
from python, but the "active_object" wasnt (and the active object was
not a mesh).

Reason for the crash is a mismatch in the operators poll function
`data_transfer_poll` vs. `dt_layers_select_src_itemf` -- in the former,
the overriden "object" was respected (and if this was a mesh, the poll
was permissive), in the later it wasnt and only the "active_object" was
used (if this was not a mesh, a crash would happen trying to get an
evaluated mesh).

Now rectify how the object which is used is being fetched -> use
`ED_object_active_context` everywhere (see also rBe560bbe1d584).

Maniphest Tasks: T96888

Differential Revision: https://developer.blender.org/D14552
2022-04-08 11:07:40 +02:00
238b442413 BLI: add missing materialize methods for virtual arrays
This does two things:
* Introduce new `materialize_compressed` methods. Those are used
  when the dst array should not have any gaps.
* Add materialize methods in various classes where they were missing
  (and therefore caused overhead, because slower fallbacks had to be used).
2022-04-08 11:07:40 +02:00
205b4c3742 Functions: parallelize materializing arrays after field evaluation
This improves performance e.g. when creating an integer attribute
based on an index field. For 4 million vertices, I measured a speedup
from 3.5 ms to 1.2 ms.
2022-04-08 11:07:40 +02:00
0b77f7a542 Geometry Nodes: avoid data copy in store named attribute node 2022-04-08 11:07:40 +02:00
a256d4bf36 BLI: add CPPType utility to copy elements to a shorter array 2022-04-08 11:07:40 +02:00
0c8b59493d Cleanup: pass the buffer length into txt_insert_buf
Also remove redundant NULL check.
2022-04-08 11:07:40 +02:00
Matheus Santos
ed305cb012 Text Editor: Get/Set region text API
Add the ability to get/set the selected text.

**Calling the new methods:**

- `bpy.data.texts["Text"].region_as_string()`
- `bpy.data.texts["Text"].region_from_string("Replacement")`
2022-04-08 11:07:40 +02:00
99a147d934 Cleanup: spelling in comments, minor reformatting changes 2022-04-08 11:07:40 +02:00
f737a254eb Cleanup: clang-format 2022-04-08 11:07:40 +02:00
Aleksi Juvani
467b1e2d72 Geometry Nodes: Add "Connected" mode to Merge by Distance node
Expose the "Connected" mode from the weld modifier in the
"Merge by Distance" geometry node. This method only merges
vertices along existing edges, but it can be much faster
because it doesn't have to build a KD Tree of all selected
points.

Differential Revision: https://developer.blender.org/D14321
2022-04-08 11:07:40 +02:00
Yevgeny Makarov
ae4894f537 Fix T86200: Properties editor rearranges columns poorly when very wide
Use a regular property split layout instead of a grid flow.
Also fix part of T65393.

Differential Revision: https://developer.blender.org/D13558
2022-04-08 11:07:40 +02:00
Ujwal Kundur
a2db5ee3e5 Fix T91541: Naming of Freestyle Curvature 3D modifier
Change the modifier name in the modifier stack to "Curvature 3D"
to be consistent with the modifier name in the drop-down.

Differential Revision: https://developer.blender.org/D14476
2022-04-08 11:07:40 +02:00
Pratik Borhade
cff0866223 Fix: UI alignment in knife tool settings popover
Remove the extra space given for decorators on right of the popover.

Differential Revision: https://developer.blender.org/D14518
2022-04-08 11:07:40 +02:00
Aleksi Juvani
3e8a9160ba Fix: Division by zero in UV packing function
If all islands had a size of zero, a division by zero would occur in
`GEO_uv_parametrizer_pack`, causing the UV coordinates to be set to
NaN. An alternative approach would be to skip packing islands with a
zero size, but If UV coordinates are for example outside the 0-1 range,
it's better if they get moved into that range.

Differential Revision: https://developer.blender.org/D14522
2022-04-08 11:07:40 +02:00
Mattias Fredriksson
07d11907a9 Fix: Copy resolution when creating CurveEval from Curves
Set the curve resolution to Bezier and Nurbs curves when converting
data using `curves_to_curve_eval`. This was missed in 9ec12c26f1.

Differential Revision: https://developer.blender.org/D14577
2022-04-08 11:07:40 +02:00
Mattias Fredriksson
2d7e3359c8 Cleanup: Incorrect comment in IndexRange header 2022-04-08 11:07:40 +02:00
23de2dae5e Curves: Name mutable data retrieval functions explicitly
Add "for_write" on function names that retrieve mutable data arrays.
Though this makes function names longer, it's likely worth it because
it allows more easily using the const functions in a non-const context,
and reduces cases of mistakenly retrieving with edit access.

In the long term, this situation might change more if we implement
attributes storage that is accessible directly on `CurvesGeometry`
without duplicating the attribute API on geometry components,
which is currently the rough plan.

Differential Revision: https://developer.blender.org/D14562
2022-04-08 11:07:40 +02:00
8a59a65fd9 Curves: Hair to Curves rename in Cycles/EEVEE UI
Change uses of "Hair" in Render Settings UI in the property editor
and the "Hair Info" node to use the "Curves" name to reflect the
design described in T95355, where hair is just a use case of a more
general curves data type.

While these settings still affect the particle hair system,
the idea is that if we have to choose one naming scheme to align
with, we should choose the option that aligns with future plans
and current development efforts, especially since the particle
system is considered a legacy feature.

A few notes:
- "Principled Hair BSDF" is not affected since it's meant for hair.
- Python API property identifiers are not affected.

Differential Revision: https://developer.blender.org/D14573
2022-04-08 11:07:40 +02:00
f873802493 Fix: Curve parameter node broken for Bezier curves after refactor
The last length value was not initialized, and all length values were
moved one position towards the front of each curve incorrectly.
Also fix an assert when a curve only had a single point.
2022-04-08 11:07:40 +02:00
57504d1b11 BVH Utils: use fall-through in 'BKE_bvhtree_from_mesh_get'
This deduplicates the code a bit.
2022-04-08 11:07:40 +02:00
42ddd87fa5 Cleanup: remove workaround to set treedata members
This workaround is not needed since
228f7f1c85
2022-04-08 11:07:40 +02:00
howetuft
69efc30bd8 Fix standalone image output not working when not running in background mode
Differential Revision: https://developer.blender.org/D14471
2022-04-08 11:07:39 +02:00
howetuft
596a9c6983 Add CMake option to control CUDA host compiler
This revision allows to specify CUDA host compiler (nvcc's -ccbin command
line option) when configuring the build. It addresses the case where the
C/C++ compiler to be used in CUDA toolchain should be different from the
default C/C++ compiler, for instance in case of compilers versions conflicts
or multiple installed compilers.

The new CMake option is named `CUDA_HOST_COMPILER` and can be used as follows:
`cmake -DCUDA_HOST_COMPILER=<path-to-host-compiler>`

If the option is not specified, the build configuration behaves as previously.

Differential Revision: https://developer.blender.org/D14248
2022-04-08 11:07:39 +02:00
8e7066f949 Fix: Missing virtual destructor on virtual class
This caused an ASAN report for new/delete type mismatch
when using the snake hook brush in curves sculpt mode.
2022-04-08 11:07:39 +02:00
631a49ce5f Fix F-Curve visibility toggle disabled for library overridden rig
When showing an action data-block added to a library overridden object
in the Graph Editor, the visibility toggles would be disabled.
Toggling the visibility should be possible still and works with the
shortcuts, just the button was incorrectly disabled.

Also added the usual disabled hint for the tooltip.

Differential Revision: https://developer.blender.org/D14568

Reviewed by: Bastien Montagne
2022-04-08 11:07:39 +02:00
b6d5c010e6 Fix T96595: Animation not duplicated for meta children
Iterate over meta strip content and duplicate animation for all strips.
recursively.
2022-04-08 11:07:39 +02:00
4a6a65f214 extend seams. 2022-04-06 17:43:28 +02:00
8a6b74b325 Improve performance by sorting pixel packages. 2022-04-06 13:46:18 +02:00
2d6ca66b7f Wrapped vector in its own class. 2022-04-06 13:23:18 +02:00
f3f77d2175 Merge branch 'master' into temp-T96710-pbvh-pixels 2022-04-06 12:24:44 +02:00
093ebb71ee Hook experimental flag to paint brush. 2022-04-04 14:31:53 +02:00
90cdb12add Merge branch 'master' into temp-T96710-pbvh-pixels 2022-04-04 14:21:48 +02:00
d60bbfdc18 Some documentation. 2022-04-04 13:51:01 +02:00
680f95ab4d Rename to EncodedBarycentricWeights. 2022-04-04 13:22:54 +02:00
eca2804a86 Barycentric weights refactoring. 2022-04-04 13:01:21 +02:00
c1945a07c2 Wrapped VisitedPolygons in a class. 2022-04-04 11:38:46 +02:00
b8c0a6c999 Rebuild pixels when active material or image changes. 2022-04-04 11:21:19 +02:00
ca30a541a0 Merge remote-tracking branch 'origin/master' into temp-T96710-pbvh-pixels 2022-04-04 08:27:46 +02:00
7137951f9c Add tagging flag for pixel update. 2022-04-01 16:05:54 +02:00
27a2c1c261 Code style. Extracted into multiple functions to improve readability. 2022-04-01 15:02:37 +02:00
560614c0dc Cleanup unused parameters. 2022-04-01 12:56:49 +02:00
843752d834 Fix memory leak 2022-04-01 12:53:58 +02:00
7fb08a4ff5 Remove print statement. 2022-04-01 12:53:40 +02:00
e2c545e1b4 Remove unused flag. 2022-04-01 12:53:23 +02:00
81f6998d65 Paint brush on images. 2022-04-01 12:31:25 +02:00
e3203434c3 Build pixels when using sculpt paint brush. 2022-04-01 12:31:25 +02:00
9a2b06bad8 PBVH Pixel extractor. 2022-03-30 14:26:42 +02:00
11 changed files with 907 additions and 3 deletions

View File

@@ -132,6 +132,28 @@ struct UDIMTilePixels {
}
};
struct SeamFixCopy {
int2 src_pixel;
int2 dst_pixel;
};
struct SeamFixBlend {
float2 src_pixel;
int2 dst_pixel;
char src_bit_mask;
};
struct UDIMSeamFixes {
uint16_t src_tile_number;
uint16_t dst_tile_number;
Vector<SeamFixCopy> pixels_to_copy;
Vector<SeamFixBlend> pixels_to_blend;
UDIMSeamFixes(uint16_t src_tile_number, uint16_t dst_tile_number)
: src_tile_number(src_tile_number), dst_tile_number(dst_tile_number)
{
}
};
struct NodeData {
struct {
bool dirty : 1;
@@ -139,6 +161,7 @@ struct NodeData {
Vector<UDIMTilePixels> tiles;
Triangles triangles;
Vector<UDIMSeamFixes> seams;
NodeData()
{
@@ -155,6 +178,17 @@ struct NodeData {
return nullptr;
}
UDIMSeamFixes &ensure_seam_fixes(uint16_t src_tile_number, uint16_t dst_tile_number)
{
for (UDIMSeamFixes &fixes : seams) {
if (fixes.src_tile_number == src_tile_number && fixes.dst_tile_number == dst_tile_number) {
return fixes;
}
}
seams.append(UDIMSeamFixes(src_tile_number, dst_tile_number));
return seams.last();
}
void mark_region(Image &image, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer)
{
UDIMTilePixels *tile = find_tile_data(image_tile);
@@ -181,4 +215,8 @@ struct NodeData {
NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node);
void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user);
void BKE_pbvh_pixels_rebuild_seams(
PBVH *pbvh, const Mesh *me, Image *image, ImageUser *image_user, const MLoopUV *ldata_uv);
void BKE_pbvh_pixels_fix_seams(PBVHNode *node, Image *image, ImageUser *image_user);
} // namespace blender::bke::pbvh::pixels

View File

@@ -247,6 +247,7 @@ set(SRC
intern/pbvh.cc
intern/pbvh_bmesh.c
intern/pbvh_pixels.cc
intern/pbvh_pixels_seams.cc
intern/pointcache.c
intern/pointcloud.cc
intern/preferences.c

View File

@@ -113,6 +113,7 @@ char *BKE_paint_canvas_key_get(struct PaintModeSettings *settings, struct Object
Image *image;
ImageUser *image_user;
if (BKE_paint_canvas_image_get(settings, ob, &image, &image_user)) {
ss << ",SEAM_DIST:" << image->seamfix_distance;
ImageUser tile_user = *image_user;
LISTBASE_FOREACH (ImageTile *, image_tile, &image->tiles) {
tile_user.tile = image_tile->tile_number;

View File

@@ -259,16 +259,47 @@ static void apply_watertight_check(PBVH *pbvh, Image *image, ImageUser *image_us
pixel_row.start_image_coordinate.x;
for (int x = 0; x < pixel_row.num_pixels; x++) {
if (image_buffer->rect_float) {
copy_v4_fl(&image_buffer->rect_float[pixel_offset * 4], 1.0);
copy_v4_fl4(&image_buffer->rect_float[pixel_offset * 4], 0.0f, 0.5f, 0.0f, 1.0f);
}
if (image_buffer->rect) {
uint8_t *dest = static_cast<uint8_t *>(
static_cast<void *>(&image_buffer->rect[pixel_offset]));
copy_v4_uchar(dest, 255);
static uint8_t color[] = {0, 128, 0, 255};
copy_v4_v4_uchar(dest, color);
}
pixel_offset += 1;
}
}
for (UDIMSeamFixes &fixes : node_data->seams) {
if (fixes.dst_tile_number != image_tile.get_tile_number()) {
continue;
}
for (SeamFixCopy &fix : fixes.pixels_to_copy) {
int pixel_offset = fix.dst_pixel.y * image_buffer->x + fix.dst_pixel.x;
if (image_buffer->rect_float != nullptr) {
copy_v4_fl4(&image_buffer->rect_float[pixel_offset * 4], 1.0f, 0.0f, 0.0f, 1.0f);
}
else if (image_buffer->rect != nullptr) {
uint8_t *dest = static_cast<uint8_t *>(
static_cast<void *>(&image_buffer->rect[pixel_offset]));
static uint8_t seam_color[] = {255, 0, 0, 255};
copy_v4_v4_uchar(dest, seam_color);
}
}
for (SeamFixBlend &fix : fixes.pixels_to_blend) {
int pixel_offset = fix.dst_pixel.y * image_buffer->x + fix.dst_pixel.x;
if (image_buffer->rect_float != nullptr) {
copy_v4_fl4(&image_buffer->rect_float[pixel_offset * 4], 1.0f, 0.0f, 0.0f, 1.0f);
}
else if (image_buffer->rect != nullptr) {
uint8_t *dest = static_cast<uint8_t *>(
static_cast<void *>(&image_buffer->rect[pixel_offset]));
static uint8_t seam_color[] = {255, 0, 0, 255};
copy_v4_v4_uchar(dest, seam_color);
}
}
}
}
BKE_image_release_ibuf(image, image_buffer, nullptr);
}
@@ -303,6 +334,9 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, nodes_to_update.size());
BLI_task_parallel_range(0, nodes_to_update.size(), &user_data, do_encode_pixels, &settings);
BKE_pbvh_pixels_rebuild_seams(pbvh, mesh, image, image_user, ldata_uv);
if (USE_WATERTIGHT_CHECK) {
apply_watertight_check(pbvh, image, image_user);
}

View File

@@ -0,0 +1,814 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. All rights reserved. */
#include "BKE_image.h"
#include "BKE_image_wrappers.hh"
#include "BKE_pbvh.h"
#include "BKE_pbvh_pixels.hh"
#include "IMB_imbuf_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_edgehash.h"
#include "BLI_vector.hh"
#include "pbvh_intern.h"
namespace blender::bke::pbvh::pixels {
struct EdgeLoop {
/** Loop indexes that form an edge. */
int l[2];
};
enum class EdgeCheckFlag {
/** No connecting edge loop found. */
Unconnected,
/** A connecting edge loop found. */
Connected,
};
struct EdgeCheck {
EdgeCheckFlag flag;
EdgeLoop first;
EdgeLoop second;
/* First vertex index of the first edge loop to determine winding order switching. */
int first_v;
};
/** Do the two given EdgeLoops share the same uv coordinates. */
bool share_uv(const MLoopUV *ldata_uv, EdgeLoop &edge1, EdgeLoop &edge2)
{
const float2 &uv_1_a = ldata_uv[edge1.l[0]].uv;
const float2 &uv_1_b = ldata_uv[edge1.l[1]].uv;
const float2 &uv_2_a = ldata_uv[edge2.l[0]].uv;
const float2 &uv_2_b = ldata_uv[edge2.l[1]].uv;
return (equals_v2v2(uv_1_a, uv_2_a) && equals_v2v2(uv_1_b, uv_2_b)) ||
(equals_v2v2(uv_1_a, uv_2_b) && equals_v2v2(uv_1_b, uv_2_a));
}
/** Make a list of connected and unconnected edgeloops that require UV Seam fixes. */
void find_edges_that_need_fixing(const Mesh *mesh,
const MLoopUV *ldata_uv,
Vector<std::pair<EdgeLoop, EdgeLoop>> &r_connected,
Vector<EdgeLoop> &r_unconnected)
{
EdgeHash *eh = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(mesh->totpoly));
for (int p = 0; p < mesh->totpoly; p++) {
MPoly &mpoly = mesh->mpoly[p];
int prev_l = mpoly.loopstart + mpoly.totloop - 1;
for (int l = 0; l < mpoly.totloop; l++) {
MLoop &prev_mloop = mesh->mloop[prev_l];
int current_l = mpoly.loopstart + l;
MLoop &mloop = mesh->mloop[current_l];
void **value_ptr;
if (!BLI_edgehash_ensure_p(eh, prev_mloop.v, mloop.v, &value_ptr)) {
EdgeCheck *value = MEM_cnew<EdgeCheck>(__func__);
value->flag = EdgeCheckFlag::Unconnected;
value->first.l[0] = prev_l;
value->first.l[1] = current_l;
value->first_v = prev_mloop.v;
*value_ptr = value;
}
else {
EdgeCheck *value = static_cast<EdgeCheck *>(*value_ptr);
if (value->flag == EdgeCheckFlag::Unconnected) {
value->flag = EdgeCheckFlag::Connected;
/* Switch winding order to match the first edge. */
if (prev_mloop.v == value->first_v) {
value->second.l[0] = prev_l;
value->second.l[1] = current_l;
}
else {
value->second.l[0] = current_l;
value->second.l[1] = prev_l;
}
}
}
prev_l = current_l;
}
}
EdgeHashIterator iter;
BLI_edgehashIterator_init(&iter, eh);
while (!BLI_edgehashIterator_isDone(&iter)) {
EdgeCheck *value = static_cast<EdgeCheck *>(BLI_edgehashIterator_getValue(&iter));
switch (value->flag) {
case EdgeCheckFlag::Unconnected: {
r_unconnected.append(value->first);
break;
}
case EdgeCheckFlag::Connected: {
if (!share_uv(ldata_uv, value->first, value->second)) {
r_connected.append(std::pair<EdgeLoop, EdgeLoop>(value->first, value->second));
r_connected.append(std::pair<EdgeLoop, EdgeLoop>(value->second, value->first));
}
break;
}
}
BLI_edgehashIterator_step(&iter);
}
BLI_edgehash_free(eh, MEM_freeN);
}
struct PixelInfo {
const static uint32_t IS_EXTRACTED = 1 << 0;
const static uint32_t IS_SEAM_FIX = 1 << 1;
uint32_t node = 0;
PixelInfo() = default;
PixelInfo(const PixelInfo &other) = default;
static PixelInfo from_node(int node_index)
{
PixelInfo result;
result.node = node_index << 2 | PixelInfo::IS_EXTRACTED;
return result;
}
static PixelInfo seam_fix()
{
PixelInfo result;
result.node = IS_SEAM_FIX;
return result;
}
uint32_t get_node_index() const
{
return node >> 2;
}
bool is_extracted() const
{
return (node & PixelInfo::IS_EXTRACTED) != 0;
}
bool is_seam_fix() const
{
return (node & PixelInfo::IS_SEAM_FIX) != 0;
}
bool is_empty_space() const
{
return !(is_extracted() || is_seam_fix());
}
};
struct Bitmap {
image::ImageTileWrapper image_tile;
Vector<PixelInfo> bitmap;
int2 resolution;
Bitmap(image::ImageTileWrapper &image_tile, Vector<PixelInfo> bitmap, int2 resolution)
: image_tile(image_tile), bitmap(bitmap), resolution(resolution)
{
}
void mark_seam_fix(int2 image_coordinate)
{
int offset = image_coordinate.y * resolution.x + image_coordinate.x;
bitmap[offset] = PixelInfo::seam_fix();
}
const PixelInfo &get_pixel_info(int2 image_coordinate) const
{
int offset = image_coordinate.y * resolution.x + image_coordinate.x;
return bitmap[offset];
}
const PixelInfo &get_pixel_info_safe(int2 image_coordinate) const
{
static PixelInfo coordinate_out_of_bounds_result;
if (image_coordinate.x < 0 || image_coordinate.y < 0 || image_coordinate.x >= resolution.x ||
image_coordinate.y >= resolution.y) {
return coordinate_out_of_bounds_result;
}
int offset = image_coordinate.y * resolution.x + image_coordinate.x;
return bitmap[offset];
}
bool contains(const float2 &uv) const
{
int2 tile_offset = image_tile.get_tile_offset();
float2 tile_uv(uv.x - tile_offset.x, uv.y - tile_offset.y);
if (tile_uv.x < 0.0f || tile_uv.x >= 1.0f) {
return false;
}
if (tile_uv.y < 0.0f || tile_uv.y >= 1.0f) {
return false;
}
return true;
}
};
struct Bitmaps {
Vector<Bitmap> bitmaps;
const Bitmap *find_containing_uv(float2 uv) const
{
for (const Bitmap &bitmap : bitmaps) {
if (bitmap.contains(uv)) {
return &bitmap;
}
}
return nullptr;
}
};
Vector<PixelInfo> create_tile_bitmap(const PBVH &pbvh,
image::ImageTileWrapper &image_tile,
ImBuf &image_buffer)
{
Vector<PixelInfo> result(image_buffer.x * image_buffer.y);
for (int n = 0; n < pbvh.totnode; n++) {
PBVHNode *node = &pbvh.nodes[n];
if ((node->flag & PBVH_Leaf) == 0) {
continue;
}
NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
UDIMTilePixels *tile_node_data = node_data->find_tile_data(image_tile);
if (tile_node_data == nullptr) {
continue;
}
for (PackedPixelRow &pixel_row : tile_node_data->pixel_rows) {
int pixel_offset = pixel_row.start_image_coordinate.y * image_buffer.x +
pixel_row.start_image_coordinate.x;
for (int x = 0; x < pixel_row.num_pixels; x++) {
result[pixel_offset] = PixelInfo::from_node(n);
pixel_offset += 1;
}
}
}
return result;
}
Bitmaps create_tile_bitmap(const PBVH &pbvh, Image &image, ImageUser &image_user)
{
Bitmaps result;
ImageUser image_tile_user = image_user;
LISTBASE_FOREACH (ImageTile *, tile_data, &image.tiles) {
image::ImageTileWrapper image_tile(tile_data);
image_tile_user.tile = image_tile.get_tile_number();
ImBuf *image_buffer = BKE_image_acquire_ibuf(&image, &image_tile_user, nullptr);
if (image_buffer == nullptr) {
continue;
}
Vector<PixelInfo> bitmap = create_tile_bitmap(pbvh, image_tile, *image_buffer);
result.bitmaps.append(Bitmap(image_tile, bitmap, int2(image_buffer->x, image_buffer->y)));
BKE_image_release_ibuf(&image, image_buffer, nullptr);
}
return result;
}
int2 find_source_pixel(const Bitmap &bitmap,
float2 near_image_coord,
const float seam_fix_distance)
{
const int SEARCH_RADIUS = std::ceil(seam_fix_distance);
float min_distance = FLT_MAX;
int2 result(0, 0);
int2 image_coord(int(near_image_coord.x), int(near_image_coord.y));
for (int v = image_coord.y - SEARCH_RADIUS; v <= image_coord.y + SEARCH_RADIUS; v++) {
for (int u = image_coord.x - SEARCH_RADIUS; u <= image_coord.x + SEARCH_RADIUS; u++) {
if (u < 0 || u >= bitmap.resolution.x || v < 0 || v >= bitmap.resolution.y) {
/** Pixel not part of this tile. */
continue;
}
int2 uv(u, v);
const PixelInfo &pixel_info = bitmap.get_pixel_info(uv);
if (!pixel_info.is_extracted()) {
continue;
}
float2 center_pixel_uv(u + 0.5f, v + 0.5f);
float distance = len_v2v2(center_pixel_uv, near_image_coord);
if (distance < min_distance) {
result = uv;
min_distance = distance;
}
}
}
return result;
}
/** Clears all existing seam fixes in the given PBVH. */
static void pbvh_pixels_clear_seams(PBVH *pbvh)
{
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode &node = pbvh->nodes[n];
if ((node.flag & PBVH_Leaf) == 0) {
continue;
}
NodeData &node_data = BKE_pbvh_pixels_node_data_get(node);
node_data.seams.clear();
}
}
static void add_seam_fix(PBVHNode &node,
uint16_t src_tile_number,
int2 src_pixel,
uint16_t dst_tile_number,
int2 dst_pixel)
{
NodeData &node_data = BKE_pbvh_pixels_node_data_get(node);
UDIMSeamFixes &seam_fixes = node_data.ensure_seam_fixes(src_tile_number, dst_tile_number);
seam_fixes.pixels_to_copy.append(SeamFixCopy{src_pixel, dst_pixel});
}
static void add_seam_fix(PBVHNode &node,
uint16_t src_tile_number,
float2 src_pixel,
char src_bit_mask,
uint16_t dst_tile_number,
int2 dst_pixel)
{
NodeData &node_data = BKE_pbvh_pixels_node_data_get(node);
UDIMSeamFixes &seam_fixes = node_data.ensure_seam_fixes(src_tile_number, dst_tile_number);
seam_fixes.pixels_to_blend.append(SeamFixBlend{src_pixel, dst_pixel, src_bit_mask});
}
/* -------------------------------------------------------------------- */
/** \name Build fixes for connected edges.
* \{ */
struct Projection {
const Bitmap *bitmap = nullptr;
int node_index = -1;
float2 pixel = float2(0.0f, 0.0f);
char bit_mask = 0;
float score = 0.0f;
};
/*
* Project the point over onto the connected UV space. Taking into account the scale
* difference.
*/
static void find_projection_source(const Bitmaps &bitmaps,
const float distance_to_edge,
const float lambda,
const MLoopUV &uv1,
const MLoopUV &uv2,
const float scale_factor,
Projection &r_projection)
{
r_projection.bit_mask = 0;
r_projection.score = 0;
r_projection.node_index = -1;
float2 closest_point;
interp_v2_v2v2(closest_point, uv1.uv, uv2.uv, lambda);
r_projection.bitmap = bitmaps.find_containing_uv(closest_point);
if (r_projection.bitmap == nullptr) {
return;
}
closest_point.x -= r_projection.bitmap->image_tile.get_tile_x_offset();
closest_point.y -= r_projection.bitmap->image_tile.get_tile_y_offset();
float2 direction;
sub_v2_v2v2(direction, uv2.uv, uv1.uv);
float2 perpedicular(direction.y, -direction.x);
normalize_v2(perpedicular);
perpedicular.x /= r_projection.bitmap->resolution.x;
perpedicular.y /= r_projection.bitmap->resolution.y;
float2 projected_coord = closest_point + perpedicular * distance_to_edge * scale_factor;
projected_coord.x *= r_projection.bitmap->resolution.x;
projected_coord.y *= r_projection.bitmap->resolution.y;
r_projection.pixel = projected_coord;
/* Check neighbouring pixels and extract mask. Pixels should be part of the same node. */
int2 pixel(std::floor(projected_coord.x), std::floor(projected_coord.y));
PixelInfo pixel_info = r_projection.bitmap->get_pixel_info_safe(pixel);
int node_index = pixel_info.get_node_index();
if (pixel_info.is_extracted() &&
(r_projection.node_index == -1 || r_projection.node_index == node_index)) {
r_projection.bit_mask |= 1;
r_projection.score += 1.0;
r_projection.node_index = node_index;
}
pixel.x += 1;
pixel_info = r_projection.bitmap->get_pixel_info_safe(pixel);
node_index = pixel_info.get_node_index();
if (pixel_info.is_extracted() &&
(r_projection.node_index == -1 || r_projection.node_index == node_index)) {
r_projection.bit_mask |= 2;
r_projection.score += 1.0;
r_projection.node_index = node_index;
}
pixel.x -= 1;
pixel.y += 1;
pixel_info = r_projection.bitmap->get_pixel_info_safe(pixel);
node_index = pixel_info.get_node_index();
if (pixel_info.is_extracted() &&
(r_projection.node_index == -1 || r_projection.node_index == node_index)) {
r_projection.bit_mask |= 4;
r_projection.score += 1.0;
r_projection.node_index = node_index;
}
pixel.x += 1;
pixel_info = r_projection.bitmap->get_pixel_info_safe(pixel);
node_index = pixel_info.get_node_index();
if (pixel_info.is_extracted() &&
(r_projection.node_index == -1 || r_projection.node_index == node_index)) {
r_projection.bit_mask |= 8;
r_projection.score += 1.0;
r_projection.node_index = node_index;
}
}
static void build_fixes(PBVH &pbvh,
Bitmaps &bitmaps,
Bitmap &bitmap,
const rcti &uvbounds,
const MLoopUV &luv_a_1,
const MLoopUV &luv_a_2,
const MLoopUV &luv_b_1,
const MLoopUV &luv_b_2,
const float scale_factor,
const float seamfix_distance)
{
if (uvbounds.xmax < 0 || uvbounds.ymax < 0 || uvbounds.xmin > bitmap.resolution.x ||
uvbounds.ymin > bitmap.resolution.y) {
return;
}
for (int v = uvbounds.ymin; v <= uvbounds.ymax; v++) {
for (int u = uvbounds.xmin; u <= uvbounds.xmax; u++) {
if (u < 0 || u >= bitmap.resolution.x || v < 0 || v >= bitmap.resolution.y) {
/** Pixel not part of this tile. */
continue;
}
int pixel_offset = v * bitmap.resolution.x + u;
PixelInfo &pixel_info = bitmap.bitmap[pixel_offset];
if (pixel_info.is_extracted() || pixel_info.is_seam_fix()) {
/* Skip this pixel as it already has a solution. */
continue;
}
float2 dst_uv_offset(bitmap.image_tile.get_tile_x_offset(),
bitmap.image_tile.get_tile_y_offset());
float2 uv_coord(u, v);
float2 center_uv_coord(u + 0.5f, v + 0.5f);
float2 center_uv(center_uv_coord.x / bitmap.resolution.x,
center_uv_coord.y / bitmap.resolution.y);
float2 closest_point;
const float lambda = closest_to_line_v2(closest_point,
center_uv,
float2(luv_a_1.uv) - dst_uv_offset,
float2(luv_a_2.uv) - dst_uv_offset);
float2 closest_coord(closest_point.x * bitmap.resolution.x,
closest_point.y * bitmap.resolution.y);
/* Distance to the edge in pixel space. */
float distance_to_edge = len_v2v2(closest_coord, center_uv_coord);
if (distance_to_edge > seamfix_distance) {
continue;
}
Projection solution1;
Projection solution2;
/* When distance to edge is small, it could happen that the solution is pointing to a pixel
* that also needs to be fixed. In this case we increase the distance until we find a
* solution or skip this pixel after some iterations. */
while (solution1.score == 0.0f && solution2.score == 0.0f) {
find_projection_source(
bitmaps, distance_to_edge, lambda, luv_b_1, luv_b_2, scale_factor, solution1);
find_projection_source(
bitmaps, distance_to_edge, 1.0f - lambda, luv_b_2, luv_b_1, scale_factor, solution2);
if (distance_to_edge > 1.4f) {
break;
}
distance_to_edge += 0.25f;
}
if (solution1.score == 0.0 && solution2.score == 0.0) {
/* No solution found skip this pixel. */
continue;
}
Projection &best_solution = solution1.score > solution2.score ? solution1 : solution2;
int2 destination_pixel(u, v);
int src_node = best_solution.node_index;
PBVHNode &node = pbvh.nodes[src_node];
add_seam_fix(node,
best_solution.bitmap->image_tile.get_tile_number(),
best_solution.pixel,
best_solution.bit_mask,
bitmap.image_tile.get_tile_number(),
destination_pixel);
bitmap.mark_seam_fix(destination_pixel);
}
}
}
static void build_fixes(PBVH &pbvh,
const Vector<std::pair<EdgeLoop, EdgeLoop>> &connected,
Bitmaps &bitmaps,
const MLoopUV *ldata_uv,
const float seamfix_distance)
{
const int margin = std::ceil(seamfix_distance);
for (const std::pair<EdgeLoop, EdgeLoop> &pair : connected) {
// determine bounding rect in uv space + margin of 1;
rctf uvbounds;
BLI_rctf_init_minmax(&uvbounds);
const MLoopUV &luv_a_1 = ldata_uv[pair.first.l[0]];
const MLoopUV &luv_a_2 = ldata_uv[pair.first.l[1]];
BLI_rctf_do_minmax_v(&uvbounds, luv_a_1.uv);
BLI_rctf_do_minmax_v(&uvbounds, luv_a_2.uv);
const MLoopUV &luv_b_1 = ldata_uv[pair.second.l[0]];
const MLoopUV &luv_b_2 = ldata_uv[pair.second.l[1]];
const float scale_factor = len_v2v2(luv_b_1.uv, luv_b_2.uv) / len_v2v2(luv_a_1.uv, luv_a_2.uv);
for (Bitmap &bitmap : bitmaps.bitmaps) {
rcti uvbounds_i;
uvbounds_i.xmin = (uvbounds.xmin - bitmap.image_tile.get_tile_x_offset()) *
bitmap.resolution[0];
uvbounds_i.ymin = (uvbounds.ymin - bitmap.image_tile.get_tile_y_offset()) *
bitmap.resolution[1];
uvbounds_i.xmax = (uvbounds.xmax - bitmap.image_tile.get_tile_x_offset()) *
bitmap.resolution[0];
uvbounds_i.ymax = (uvbounds.ymax - bitmap.image_tile.get_tile_y_offset()) *
bitmap.resolution[1];
uvbounds_i.xmin -= margin;
uvbounds_i.xmax += margin;
uvbounds_i.ymin -= margin;
uvbounds_i.ymax += margin;
build_fixes(pbvh,
bitmaps,
bitmap,
uvbounds_i,
luv_a_1,
luv_a_2,
luv_b_1,
luv_b_2,
scale_factor,
seamfix_distance);
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Build fixes for unconnected edges.
* \{ */
static void build_fixes(PBVH &pbvh,
Bitmap &bitmap,
const rcti &uvbounds,
const MLoopUV &luv_1,
const MLoopUV &luv_2,
const float seamfix_distance)
{
if (uvbounds.xmax < 0 || uvbounds.ymax < 0 || uvbounds.xmin > bitmap.resolution.x ||
uvbounds.ymin > bitmap.resolution.y) {
return;
}
for (int v = uvbounds.ymin; v <= uvbounds.ymax; v++) {
for (int u = uvbounds.xmin; u <= uvbounds.xmax; u++) {
if (u < 0 || u >= bitmap.resolution[0] || v < 0 || v >= bitmap.resolution[1]) {
/** Pixel not part of this tile. */
continue;
}
int pixel_offset = v * bitmap.resolution[0] + u;
PixelInfo &pixel_info = bitmap.bitmap[pixel_offset];
if (pixel_info.is_extracted() || pixel_info.is_seam_fix()) {
/* Skip this pixel as it already has a solution. */
continue;
}
float2 dst_uv_offset(bitmap.image_tile.get_tile_x_offset(),
bitmap.image_tile.get_tile_y_offset());
float2 uv(float(u) / bitmap.resolution[0], float(v) / bitmap.resolution[1]);
float2 closest_point;
closest_to_line_v2(
closest_point, uv, float2(luv_1.uv) - dst_uv_offset, float2(luv_2.uv) - dst_uv_offset);
/* Calculate the distance in pixel space. */
float2 uv_coord(u, v);
float2 closest_coord(closest_point.x * bitmap.resolution.x,
closest_point.y * bitmap.resolution.y);
float distance_to_edge = len_v2v2(uv_coord, closest_coord);
if (distance_to_edge > seamfix_distance) {
continue;
}
int2 source_pixel = find_source_pixel(bitmap, closest_coord, seamfix_distance);
int2 destination_pixel(u, v);
PixelInfo src_pixel_info = bitmap.get_pixel_info(source_pixel);
if (!src_pixel_info.is_extracted()) {
continue;
}
int src_node = src_pixel_info.get_node_index();
PBVHNode &node = pbvh.nodes[src_node];
add_seam_fix(node,
bitmap.image_tile.get_tile_number(),
source_pixel,
bitmap.image_tile.get_tile_number(),
destination_pixel);
bitmap.mark_seam_fix(destination_pixel);
}
}
}
static void build_fixes(PBVH &pbvh,
const Vector<EdgeLoop> &unconnected,
Bitmaps &bitmaps,
const MLoopUV *ldata_uv,
const float seamfix_distance)
{
for (const EdgeLoop &unconnected_loop : unconnected) {
// determine bounding rect in uv space + margin of 1;
rctf uvbounds;
BLI_rctf_init_minmax(&uvbounds);
const MLoopUV &luv_1 = ldata_uv[unconnected_loop.l[0]];
const MLoopUV &luv_2 = ldata_uv[unconnected_loop.l[1]];
BLI_rctf_do_minmax_v(&uvbounds, luv_1.uv);
BLI_rctf_do_minmax_v(&uvbounds, luv_2.uv);
for (Bitmap &bitmap : bitmaps.bitmaps) {
rcti uvbounds_i;
const int MARGIN = 1;
uvbounds_i.xmin = (uvbounds.xmin - bitmap.image_tile.get_tile_x_offset()) *
bitmap.resolution[0] -
MARGIN;
uvbounds_i.ymin = (uvbounds.ymin - bitmap.image_tile.get_tile_y_offset()) *
bitmap.resolution[1] -
MARGIN;
uvbounds_i.xmax = (uvbounds.xmax - bitmap.image_tile.get_tile_x_offset()) *
bitmap.resolution[0] +
MARGIN;
uvbounds_i.ymax = (uvbounds.ymax - bitmap.image_tile.get_tile_y_offset()) *
bitmap.resolution[1] +
MARGIN;
build_fixes(pbvh, bitmap, uvbounds_i, luv_1, luv_2, seamfix_distance);
}
}
}
/** \} */
void BKE_pbvh_pixels_rebuild_seams(
PBVH *pbvh, const Mesh *mesh, Image *image, ImageUser *image_user, const MLoopUV *ldata_uv)
{
// find seams.
// for each edge
Vector<std::pair<EdgeLoop, EdgeLoop>> connected;
Vector<EdgeLoop> unconnected;
find_edges_that_need_fixing(mesh, ldata_uv, connected, unconnected);
// Make a bitmap per tile indicating pixels that have already been assigned to a PBVHNode.
Bitmaps bitmaps = create_tile_bitmap(*pbvh, *image, *image_user);
pbvh_pixels_clear_seams(pbvh);
/* Fix connected edges before unconnected to improve quality. */
build_fixes(*pbvh, connected, bitmaps, ldata_uv, image->seamfix_distance);
build_fixes(*pbvh, unconnected, bitmaps, ldata_uv, image->seamfix_distance);
}
static float4 blend_source(ImBuf *src_image_buffer, float2 src_coordinate, char src_bit_mask)
{
int2 src_pixel(std::floor(src_coordinate.x), std::floor(src_coordinate.y));
int src_offset = src_pixel.y * src_image_buffer->x + src_pixel.x;
float2 frac(src_coordinate.x - src_pixel.x, src_coordinate.y - src_pixel.y);
float4 color(0.0f, 0.0f, 0.0f, 0.0f);
float sum_factor = 0.0f;
if (src_bit_mask & 1) {
float4 c1(src_image_buffer->rect_float[src_offset * 4]);
float f1 = std::sqrt(std::pow(1.0f - frac.x, 2)) + std::pow(1.0f - frac.y, 2);
color = color + c1 * f1;
sum_factor += f1;
}
if (src_bit_mask & 2) {
float4 c2(src_image_buffer->rect_float[(src_offset + 1) * 4]);
float f2 = std::sqrt(std::pow(frac.x, 2)) + std::pow(1.0f - frac.y, 2);
color = color + c2 * f2;
sum_factor += f2;
}
if (src_bit_mask & 4) {
float4 c3(src_image_buffer->rect_float[(src_offset + src_image_buffer->x) * 4]);
float f3 = std::sqrt(std::pow(1.0 - frac.x, 2)) + std::pow(frac.y, 2);
color = color + c3 * f3;
sum_factor += f3;
}
if (src_bit_mask & 8) {
float4 c4(src_image_buffer->rect_float[(src_offset + src_image_buffer->x + 1) * 4]);
float f4 = std::sqrt(std::pow(frac.x, 2)) + std::pow(frac.y, 2);
color = color + c4 * f4;
sum_factor += f4;
}
color.x /= sum_factor;
color.y /= sum_factor;
color.z /= sum_factor;
color.w = 1.0f;
return color;
}
void BKE_pbvh_pixels_fix_seams(PBVHNode *node, Image *image, ImageUser *image_user)
{
NodeData &node_data = BKE_pbvh_pixels_node_data_get(*node);
ImageUser iuser = *image_user;
for (UDIMSeamFixes &fixes : node_data.seams) {
iuser.tile = fixes.dst_tile_number;
ImBuf *dst_image_buffer = BKE_image_acquire_ibuf(image, &iuser, nullptr);
if (dst_image_buffer == nullptr) {
continue;
}
iuser.tile = fixes.src_tile_number;
ImBuf *src_image_buffer = BKE_image_acquire_ibuf(image, &iuser, nullptr);
if (src_image_buffer == nullptr) {
continue;
}
/** Determine the region to update by checking actual changes. */
rcti region_to_update;
BLI_rcti_init_minmax(&region_to_update);
if (src_image_buffer->rect_float != nullptr && dst_image_buffer->rect_float != nullptr) {
for (SeamFixCopy &fix : fixes.pixels_to_copy) {
int src_offset = fix.src_pixel.y * src_image_buffer->x + fix.src_pixel.x;
int dst_offset = fix.dst_pixel.y * dst_image_buffer->x + fix.dst_pixel.x;
if (equals_v4v4(&dst_image_buffer->rect_float[dst_offset * 4],
&src_image_buffer->rect_float[src_offset * 4])) {
continue;
}
BLI_rcti_do_minmax_v(&region_to_update, fix.dst_pixel);
copy_v4_v4(&dst_image_buffer->rect_float[dst_offset * 4],
&src_image_buffer->rect_float[src_offset * 4]);
}
for (SeamFixBlend &fix : fixes.pixels_to_blend) {
float4 color = blend_source(src_image_buffer, fix.src_pixel, fix.src_bit_mask);
int dst_offset = fix.dst_pixel.y * dst_image_buffer->x + fix.dst_pixel.x;
if (equals_v4v4(&dst_image_buffer->rect_float[dst_offset * 4], color)) {
continue;
}
BLI_rcti_do_minmax_v(&region_to_update, fix.dst_pixel);
copy_v4_v4(&dst_image_buffer->rect_float[dst_offset * 4], color);
}
}
else if (src_image_buffer->rect != nullptr && dst_image_buffer->rect != nullptr) {
for (SeamFixCopy &fix : fixes.pixels_to_copy) {
int src_offset = fix.src_pixel.y * src_image_buffer->x + fix.src_pixel.x;
int dst_offset = fix.dst_pixel.y * dst_image_buffer->x + fix.dst_pixel.x;
if (dst_image_buffer->rect[dst_offset] == src_image_buffer->rect[src_offset]) {
continue;
}
BLI_rcti_do_minmax_v(&region_to_update, fix.dst_pixel);
dst_image_buffer->rect[dst_offset] = src_image_buffer->rect[src_offset];
}
}
/* Mark dst_image_buffer region dirty covering each dst_pixel. */
if (BLI_rcti_is_valid(&region_to_update)) {
LISTBASE_FOREACH (ImageTile *, image_tile, &image->tiles) {
if (image_tile->tile_number != fixes.dst_tile_number) {
continue;
}
BKE_image_partial_update_mark_region(
image, image_tile, dst_image_buffer, &region_to_update);
break;
}
}
BKE_image_release_ibuf(image, src_image_buffer, nullptr);
BKE_image_release_ibuf(image, dst_image_buffer, nullptr);
}
}
} // namespace blender::bke::pbvh::pixels

View File

@@ -2780,6 +2780,12 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Keep this block, even when empty. */
if (!DNA_struct_elem_find(fd->filesdna, "Image", "float", "seamfix_distance")) {
LISTBASE_FOREACH (Image *, image, &bmain->images) {
image->seamfix_distance = 2.5f;
}
}
/* Replace legacy combine/separate color nodes */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
/* In geometry nodes, replace shader combine/separate color nodes with function nodes */

View File

@@ -366,6 +366,7 @@ static void do_mark_dirty_regions(void *__restrict userdata,
{
TexturePaintingUserData *data = static_cast<TexturePaintingUserData *>(userdata);
PBVHNode *node = data->nodes[n];
BKE_pbvh_pixels_fix_seams(node, data->image_data.image, data->image_data.image_user);
BKE_pbvh_pixels_mark_image_dirty(*node, *data->image_data.image, *data->image_data.image_user);
}

View File

@@ -948,6 +948,7 @@ void uiTemplateImage(uiLayout *layout,
}
uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE);
uiItemR(col, &imaptr, "seamfix_distance", 0, NULL, ICON_NONE);
}
}

View File

@@ -24,6 +24,7 @@
.gpuframenr = INT_MAX, \
.gpu_pass = SHRT_MAX, \
.gpu_layer = SHRT_MAX, \
.seamfix_distance = 2.5f, \
}
/** \} */

View File

@@ -175,7 +175,9 @@ typedef struct Image {
short gpu_pass;
short gpu_layer;
short gpu_view;
char _pad2[4];
/* Thickness of the UV seam fix area in distance between pixels and edges in pixel space. */
float seamfix_distance;
/** Deprecated. */
struct PackedFile *packedfile DNA_DEPRECATED;

View File

@@ -1160,6 +1160,11 @@ static void rna_def_image(BlenderRNA *brna)
"Use 16 bits per channel to lower the memory usage during rendering");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_gpu_texture_update");
prop = RNA_def_property(srna, "seamfix_distance", PROP_FLOAT, PROP_PIXEL);
RNA_def_property_ui_text(
prop, "Seam-fix Distance", "Pixels closer to edge will be considered during UV seam fixing");
RNA_def_property_ui_range(prop, 0.0, FLT_MAX, 1, 1);
/* multiview */
prop = RNA_def_property(srna, "views_format", PROP_ENUM, PROP_NONE);
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);