Applying Subdivision/Multires Modifier De-merges UV's #81065
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
16 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#81065
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Update
The issue of custom-data (UV's specifically) becoming detached remains, this problem existed before
b88dd3b8e7
, it was just less obvious since selection connected near-by UV's. Now UV's are merged by default at a very low threshold when applying modifiers to mitigate the problem. Keeping this report open as it would be good if subdivision-surface didn't separate UV's, replies to this report contain some notes that could lead to a solution. In practice users should not experience problems caused by this behavior, so marking low priority. ~ @campbellbarton.System Information
Operating system: Windows-10-10.0.18362-SP0 64 Bits
Graphics card: Radeon (TM) RX 480 Graphics ATI Technologies Inc. 4.5.14736 Core Profile Context 20.8.3 27.20.12027.1001
Blender Version
Broken: version: 2.91.0 Alpha, branch: master, commit date: 2020-09-22 12:02, hash:
8d1123ba22
Worked: working in 2.90
Caused by
b88dd3b8e7
Short description of error
When applying a subdivision modifier, certain UV's points disconnect from their neighbors. This does not seem to occur with the F3 menu subdivide operation.
Exact steps for others to reproduce the error
This does not seem to be an issue with the newly added
9a52b30cc0
in my eyes, rather an issue with subdividing.UV Disconnect.blend
Added subscriber: @Bobo_The_Imp
#92201 was marked as duplicate of this issue
#89903 was marked as duplicate of this issue
#89565 was marked as duplicate of this issue
#86896 was marked as duplicate of this issue
#85443 was marked as duplicate of this issue
#84419 was marked as duplicate of this issue
Added subscribers: @ideasman42, @mano-wii
One way to find out if a face is disconnected is to move it:
But I'm not sure if this is really a bug.
I'm not sure what the UV editor considers "connected".
But we cannot guarantee 100% accuracy in all operations.
(CC @ideasman42)
Perhaps it's not a bug, I'm not sure, however I do know that it is certainly undesirable behavior. I think that if UV's were merged before any operation, then they should stay that way, unless specifically told to do otherwise, like in a cut operation etc. Perhaps it's not just related to this issue, but it's an underlying quirk with the UV workflow currently? Thanks for your time.
Added subscriber: @iss
Changed status from 'Needs Triage' to: 'Confirmed'
I can confirm this working in 2.90, broken somewhere between
396d39c6b9
and0721fbb6e1
Added subscriber: @mont29
This is caused by
b88dd3b8e7
. @ideasman42 so I would say there is no bug here? subsurf probably generates small differences in UV coordinates due to numerical instability, this used to be ignored by UV selection code, now user should ensure those are perfectly matching using the merge tool first?Added subscriber: @Dabreiss
Added subscribers: @MassimilianoPuliero, @filedescriptor
Added subscribers: @Vyach, @lichtwerk
poke. Bug still here and it is important!
Added subscribers: @alvaroperez, @PratikPB2123
Added subscriber: @martinium
if bug is «unsolvable», why don
t we have just workaround (merge by distance)? at least it will eliminate issue on the user
s side.I think the whole behavior of breaking uvs by moving polys is just not right and this is creating huge issues when exporting to meshes to other software. Also causing render engine errors. And there is no way to actually visualize if you accidentally have "De-merged UVs".
Breaking of UVs should only be possible on user's explicit demand. Right now, if you just start moving verts or poligons in the UV editor with the wrong "Sticky selection mode" you can make a huge mess without noticing. I am not sure what the intention of these "modes" is, but it all looks totally broken and buggy to be honest.
Added subscriber: @Chang-Chin-Wen
Added subscriber: @dr.sybren
b88dd3b8e7
doesn't mention any benefit to users, nor does it reference any review / design document / official decision to change the behaviour. More importantly, this change was also not mentioned in the 2.91 release notes, so I would say it's fair to consider it a bug.Applying Subdivision Modifier De-merges UV'sto Applying Subdivision/Multires Modifier De-merges UV'sAdded subscribers: @Zunio, @JulienKaspar, @OmarEmaraDev, @Sergey
Agree this is a bug. At the time of committing this I wasn't aware of any user-visible changes or that the subdivision surface modifier was splitting up loop custom-data (including UV's).
Using an epsilon when comparing UV's for selection only hid the bug that was already there, this should be resolved in the subdivision surface modifier since UV selection isn't the only area that checks if UV's are in the same location (calculating tangents for example will be impacted by this).
Reverting
b88dd3b8e7
would only be a partial fix, even for selection as there are multiple selection operations that walk around co-located UV's (UV rip, loop select, path selection - for e.g.).Worse, the behavior of these operations wouldn't be deterministic - as matching all other UV locations could succeed or fail based on the UV of the initial loop which the others are compared too.
A stop-gap solution to this could be to merge UV's after applying the subdivision surface modifier (when the apply modifier operator is used to avoid adding overhead to updates for the viewport), although it would be better to investigate the problem in the subdivision-surface logic as this impacts all custom-data, not just UV's.
Added subscriber: @Chris-Blackbourn
It's possible the subdiv surface modifier is deterministic for XYZ, but not UV. If this is the case, making the UV deterministic also should fix the problem.
I've managed to repro locally and will try investigate further...
As it's tedious to reproduce this manually each time, here is a script to redo the steps: P2905: Reproduce: #81065
@ideasman42, it is still unclear to me what the user benefit in
b88dd3b8e7
is.I am not sure making bit-perfect match of UV coordinates calculated from 2 different ptex faces is something doable in practice. It is hard to guarantee order of math operations along ptex face is the same for every side of the a seam, especially taking an external nature of the library.
Surely, having that figured out would be nice, but I do not think it is cool at all to dump extra work on others without any communication upfront, without any agreed-on design. The denial to clearly user benefits of the change which would overweight measurable regression does not help motivation either. While I can see that previous situation was not ideal, reverting the commit will bring Blender to a state which was known to work (with its limitations) for a long time, and will give time to re-asses the situation by all involved modules without stretching tight schedule. So to me a revert would still be better than dragging a real regression for such a long time.
The XYZ coordinates are being calculated bit-perfect, so we know it is possible. The question is, why are the UVs not also bit-perfect?
Sure, we know how to merge-nearby and sweep the problem under the rug, but I think it's worth identifying the root-cause while we have a live repro before coming up with solutions.
I am not really sure how we know this.
For the Mesh codepath subdivided vertex positions along the edge are calculated from a single ptex face. Now when I think about it, it is not even strictly determined which ptex will be used for this due to a threaded evaluation nature. The UVs are evaluated for every point (including the ptex face boundary), since there night be discontinuation involved due to seams.
For the CCG codepath the coordinates are stitched together along the ptex face boundaries.
A possible solution would be to implement similar to coordinates heuristic and handle UV data in a special way: which is evaluate it only using single ptex when the edge between faces is not marked as seam. The downsides of this approach:
@Sergey there is no real user benefit to
b88dd3b8e7
on it's own, however - making all selection tools properly respect this is bigger project (loop select, path select, UV rip, edge selection - which checks connected UV's), which would likely incur the overhead of a merge-by-distance for each user action.At the time it didn't seem like users were depending on this functionality & even now, it's quite a spesific situation that shows up as a problem.
Even if the math isn't accurate between adjacent uv-loops these calculations could be shared as the same loop-interpolation could be used for adjacent loops.
This wasn't my intention as this could be solved at different levels (some not involving much in the way of opensubdiv development).
My resistance to revert
b88dd3b8e7
is that someone can immediately report the same issue with other selection tools, which don't useBM_uv_vert_map_create
.Basically to properly support this kind of selection, it means selection methods that use connectivity checks need to do a "merge by distance" (or behave as if that's been applied).
At that point I think we could consider doing that as part of the "Apply Modifier" action as it's not efficient to do this on every user action and as mentioned already, disconnected UV's can cause issues elsewhere.
Possible Solutions
b88dd3b8e7
, create a new report with remaining issues where disconnected UV's don't work properly.At the risk of missing the point, is it easy for someone to compile opensubdiv with -fno-fast-math -fno-fma -debug etc and report back if the bugged script^^ still repros?
I still feel like we need to identify the root-cause.
Just a quick update with my latest findings, the rounding error appears to be introduced somewhere inside this Blender function call:
That code eventually resolves out to an opensubdiv evaluator.
On the opensubdiv side, there appears to be a whole family of different evaluation engines. FWIW, the CPU version of the code appears something like this :
These kinds of loops are sensitive to round-off error.
My next step is to get a copy of the actual contents of the buffers at the time we get different results. From there we can start looking at possible fixes and their performance trade-offs.
After examining the contents of the buffers, I've managed to extract a tighter repro:
Left is original mesh, right is after one subdiv and a little bit of adjusting UVs to make the demerge more obvious.
The bug doesn't seem to be particularly sensitive to initial UVs. However the output from opensubdiv appears to be rounding the last binary digit in a way I don't yet understand.
My current working theory is that difference seems to be related to the numbering of the vertices in the face. e.g. If four vertices are numbered 12, 24, 36, 48, then the same quad can be represented as [12, 24, 36, 48] or [24, 36, 48, 12], etc.
...Investigation continues...
OK, here's two simple .OBJ files. The vertices and UVs are in identical locations, the quads are geometrically the same, but have different representations:
To repro the bug, import the second .OBJ, add a subdiv modifier (default settings), apply the modifier, then edit the UVs on the new mesh.
Note that by the "Hairy Ball Theorem", in the general case, it's not possible to find a rotation of the vertex indices inside the quads which will fix this problem.
At this point, I'm also not confident we can fix the problem upstream in OpenSubDiv without a substantial performance hit for large meshes.
I feel like the best solution is to merge UVs that are within one ULP (or 2 ULPs?) when we copy back the output from OpenSubDiv, and just eat the threading complexity and performance hit at that stage.
I've also considered just truncating the output (or input) from OpenSubDiv. While that's certainly fast, I think it only decreases the probability of a demerge, rather than eliminating it completely.
Any thoughts before I attempt to write the merge code?
p.s. Note that this fix will not be stable across machines.. e.g. Two different machines can load the same .blend file, and produce different results at the ULP level.... Is this a problem?
Keeping in mind the fact that a new report is needed for the issues brought back by the revert (as opposite of linking existing one), and that the commit caused quite serious disruption in artists workflow at the studio, this proposal seems to be the best corse or actions.
It could be a viable solution, but an investigation is needed w.r.t the merge distance.
Although, I like the sound of the idea that it will cover all possible modifiers. Also like Chris's idea of basing it on ULP.
I'm still not sure why subsurf is the only victim here. There are many other modifiers which potentially has the same issue.
We already have "Merge By Distance" operator, so I guess the majority of the code is already in place, and "just" need to find good distance.
P.S. AFAIR, it is now possible to use double floating precision in OpenSubdiv. Maybe it will help mitigating some of the precision issues (with memory usage hit).
It happens also with bevel modifier, infact I use a script to merge back the UVs.
Bevel may create new and unpredicted geometry. Subdiv only divides it with a strict rules.
Yes, it will be great to have proper UVs or more solid material division after Bevel.
Update: I have a "proof-of-concept" fix that "works on my machine" by just merging UVs as we copy them out of OpenSubdiv. This seems to pass all the tests above.
It turns out even ±3 ULP was still demerging, so I had to use a full tolerance.
I think instead of just blindly merging UVs, we should first check to see if the XYZs match, as the UVs might simply be nearby because we've joined multiple original meshes into one mesh with multiple linked components.
...plus threading...
I haven't had a chance to look at the bevel modifier, but perhaps we can use a similar approach there if we can get a fix working here.
This would have been good to mention early on as it's the first I've heard of this causing more serious problems. I'd assumed this was a fairly rare case which users could working using weld by distance. In that case adding back a threshold seems OK even if it's not leaving Blender in an ideal state in other respects. I'll look into this.
More puzzling evidence, I wanted to try and confirm that OpenSubdiv has the same output as Blender when operating on those .OBJs I posted earlier.
I built OpenSubdiv from source, passed in both SubDivRoundingSuccess.obj and SubDivRoundingProblem.obj and... to my surprise ... both outputs from OpenSubdiv had merged UVs correctly. (!)
After a little bit more digging, OpenSubdiv does indeed generate 25 unique UVs for both test cases, however those two test cases disagree on the U-coordinate for one of those UVs by exactly one ULP.
Keep in mind, the only difference between the test cases is the numbering of the vertices within the quads. Everything else is the same. Very puzzling outputs indeed.
EDIT: "25 unique UVs" was "9 unique UVs"
This comment got me thinking.. I just rechecked the XYZ positions using OpenSubdiv, and have managed to construct 2 .OBJ files which are identical up to a relabeling, and now the same thing is happening with XYZ as with UV.
i.e. I have two .OBJ files (identical up to relabeling) which OpenSubdiv both subdivide to 25 unique XYZ and 25 unique UV, but they disagree on one particular XYZ and one particular UV at the significance of 1 ULP.
i.e. The XYZ are not being calculated bit perfect by OpenSubdiv.
Next step, can we also create a de-merging of XYZ in Blender???
A tale of two OBJ files, identical up to a relabeling of the vertices within faces.
The two files, (each with 9 unique XYZ and 9 unique UV) are each subdivided in either OpenSubdiv or Blender, then the output is compared.
The preferred outcome is each output should contain 25 unique XYZ and 25 unique UV, and they should both be identical up to a relabelling.
...however...
In OpenSubdiv, each file produces 25 unique XYZ and 25 unique UV, but the two outputs disagree in the ULP.
In Blender, one of the files produces 25 unique XYZ, and 25 unique UV.
The other file produces 25 unique XYZ, and 28 (!) unique UVs.
In Blender (as in OpenSubdiv), the two outputs disagree in both XYZ and UV in the ULP.
This is strong evidence that there is another method of copying the UV information out of OpenSubdiv in a way that keeps UVs merged in the expected way.
... the investigation shifts back to Blender.
Turns out we're not the only ones having this problem. OpenSubdiv provides an alternative interface for face varying data called a Far::PrimvarRefiner for exactly this situation.
https://graphics.pixar.com/opensubdiv/docs/doxy_html/a00081.html
It looks like we already use this interface within the Cycles renderer.
I've created a Frankenstein version of blender to use this interface and it does indeed fix the problem for my limited test case.
As an added bonus, this interface appears to be more efficient than our current evaluation strategy for face varying data. We could potentially be looking at a win-win fix here for both performance and functionality.
Next step is to work up the change to something more realistic and see if it still holds on the other test cases.
p.s. I haven't had a chance to look at the issue with the Bevel modifier. If anyone is keen to isolate a repro there, it would be useful to take a peek while I have everything open in the debugger.
Okay, I think I've taken this about as far as I can.
I think the correct solution is to use Far::PrimvarRefiner to generate the UVs so that they are correctly shared across the loops.
As an added bonus, this method should be faster than the current method of evaluating each vertex of the loop using the relevant patch.
I have a version working locally that fixes the problem for simple test cases, however it:
Note that this is a subdiv-only solution, and doesn't address any other demerge situations.
I'm happy to do a handover of the testcases and code I've developed so far, but I feel I've crossed my point of diminishing returns on this task at this time.
Added subscriber: @DanielBystedt
I'm just throwing in my two cents here.
It sounds like a reasonable solution to this issue would be to do the following when one or several modifiers are applied to an object:
Merge uv's that "belong" to the same vertex and are within a small (arbitrary) distance from each other in uv space.
Discussed with Sergey and we agree it's a reasonable option, uploaded a patch D14841.
Note that this it would still be good to resolve the issue with opensubdiv, but it's not as pressing if merging is performed.
Okay, it is partial solution. But.
Imagine overlapping islands. Their cordinates are identical.
So I suppose they will merge together if you will merge by distance without any restrictions.
Also they merge if UV the same, I suppose. It is unwanted behavior for game artists, who use overlapped uv`s very often and want o keep ability to separate islands.
For example I bought stock-model with overlapped face and I want to separate halves and paint them individually.
Here is an issue: #97858 (UV: Overlapped vertices with same geometry and positions meged (unwanted merge))
@Vyach merging would only take place if the UV share a vertex. The issue with detecting islands as separate isn't changed by D14841 (compared to reverting
b88dd3b8e7
).Added subscriber: @Chris_Blackbourn
Great call, nice resolution. Code looks like it will address the problem with minimal side effects. Do you want me to try run it against my test cases here?
Agreed, priority is much lower with D14841, it becomes more of a performance issue at that point.
I'll park these resources here in case someone wants to pick it up later:
The two .OBJ files:
SubDivProblemXYZ.obj SubDivSuccessXYZ.obj
A change to the Blender OBJ exporter to support high precision verts and uvs:
export_obj_precision.diff