Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes of Quads and NGons. #138

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open

Fixes of Quads and NGons. #138

wants to merge 17 commits into from

Conversation

mifth
Copy link

@mifth mifth commented Oct 27, 2024

Hi, I did fixes for Quads and NGons. Now all works as a charm without crashes!

My video explanation of changes:
https://youtu.be/d9MWNfvQLtc

Some key points:

  • AddMesh() function was fixed
  • "polygon" variable was converted to an Array to have an unlimited amount of points for NGons.
  • indicesIDs array is added to apply ids
  • Fixed indices.
  • triangulatePolygon() was updated. It also outputs indicesIDs.
  • Changes were tested in Blender with many objects which had Quads and NGons. All warks like a charm!

Without these changes XAtlas will be crashing.

Pics:
image

image

image

image

image

Generated UVs in Blender with XAtlas:
image
image

image
image

@mifth
Copy link
Author

mifth commented Oct 28, 2024

Update. I've changed the faceVertexCount to uint32_t as potentially an NGon can have 1000000 indices/points. It can be easily done if a geometry was generated with procedural tools like Houdiny/Blender(GeometryNodes).

69b139d

Here is a simple example how heavy the NGon can be:
image

@mifth
Copy link
Author

mifth commented Oct 29, 2024

Update:

1 I've moved the indicesIDs array to the Triangulator struct.
45d673c

2 I've fixed zero area calculation for NGons in the AddMesh() function.
0a96bd1
#135 (comment)

Before:
image

After:
image
image

@mifth
Copy link
Author

mifth commented Nov 4, 2024

Update:

I made final changes to the Quads/NGons support. Now all works without any artifacts!
My commit: 22f4d64

  • computeBoundaryIntersection variable is added to ChartOptions to remove artifacts (little charts). By default it's false.
  • lots of Quads and NGons fixes.
  • No changes to a generation of triangulated meshes.

I recorded a video according to this update to show and tell about new changes:
https://youtu.be/a4NF1gcR3O8

Further discussion can be here: #135

Some pictures of a final result after a generation:
image
image
image
image
image

Some pictures to explain a new computeBoundaryIntersection variable which I've added with the latest commit.
image
image
image
image

@mifth
Copy link
Author

mifth commented Nov 4, 2024

@jpcy could you please review my pull request. I worked hard to deliver Quads/NGons support.

@castano
Copy link

castano commented Nov 4, 2024

I think that computeBoundaryIntersection serves a valid purpose and simply disabling it is not the right solution. When using LSCM the resulting charts can sometimes self-overlap. It appears that this function tries to detect these overlaps in order to penalize these parameterizations. I think this code was @jpcy's addition, so I'm not familiar with it enough to comment what could be going on, but it appears there may be a bug that's causing some valid paramterizations to be rejected. It would be much more useful to investigate the problem in more detail to understand what's happening, or to provide a repro case so that others can take a look.

@mifth
Copy link
Author

mifth commented Nov 4, 2024

Hi @castano thank you so much for your feedback. Yeah, I agree that the computeBoundaryIntersection might have be a bug or just designed the way when it fails in some cases.

Actually, I tried XAtlas with computeBoundaryIntersection=false on many models and all worked perfectly. As far as I get the LSCM unwrapping is set by default so I had no issues with this mode. I think having a boolean parameter to switch on/off the BoundaryIntersection feature is a good way too to have a possibility to change it (especially if it's buggy :) ).

I've attached a model where you could test the issue:
Monkey_smart_triangulation.zip

@mifth
Copy link
Author

mifth commented Nov 4, 2024

Sorry, forgot to mention that to reproduce the artifacts just run this simple code:

xatlas::Atlas* atlas = xatlas::Create();
xatlas::AddMeshError meshError = xatlas::AddMesh(atlas, meshDecl);  // Add your Mesh
xatlas::ChartOptions chartOptions = xatlas::ChartOptions();
xatlas::PackOptions packOptions = xatlas::PackOptions();
xatlas::Generate(atlas, chartOptions, packOptions);

@@ -5175,14 +5205,22 @@ struct PlanarCharts
m_regionFirstFace.clear();
m_nextRegionFace.resize(faceCount);
m_faceToRegionId.resize(faceCount);
const bool hasQuadsOrNGons = m_data.mesh->trianglesToPolygonIDs.size() > 0 ? true : false;
Array<bool> parsedFaces; // For Quads/NGons

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

miiiiight be beneficial to use std::vector since it'll use that weirdo pseudo bitfield implementation that will reduce memory by a factor 8. Memory consumption by geometry is revealing to be a problem in some scene cases I'm encountering with 100 millions triangles. Maybe less bandwidth can also improve caching and speed, even if it sounds in contradiction with the bit masking and shifts necessary. In GPU talks we say "ALU is free". probably can apply here.

@@ -7280,7 +7385,8 @@ class Chart
// Computing charts checks for flipped triangles and boundary intersection. Don't need to do that again here if chart is planar.
if (m_type != ChartType::Planar && m_generatorType != segment::ChartGeneratorType::OriginalUv) {
XA_PROFILE_START(parameterizeChartsEvaluateQuality)
m_quality.computeBoundaryIntersection(m_unifiedMesh, boundaryGrid);
if (options.computeBoundaryIntersection) // intersect edges. It can create artifacts (little peeces).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

little pieces ?

@siliconvoodoo
Copy link

Nice that you put so many code captures and the video walkthrough to explain your changes. 👍

@castano
Copy link

castano commented Nov 5, 2024

Actually, I tried XAtlas with computeBoundaryIntersection=false on many models and all worked perfectly.

I tried this on the model you provided and noticed that it produced a self-intersection.

image

This is the kind of error that the boundary intersection code is intended to detect.

I think the charts that have an invalid parameterization may fall back to the "piecewise" parameterization method and that may be causing the artifacts that you have detected.

A better solution may be to add an option to avoid the piecewise parameterization fallback. An even better solution would be to figure out why the piecewise parameterization method is producing these results and try to improve them. Eliminating the self-intersection tests is not a good solution.

I have not reviewed the code changes that add support for n-gons, but at the very least, I think this should be addressed in a separate PR.

@mifth
Copy link
Author

mifth commented Nov 5, 2024

@siliconvoodoo thank you so much for your feedback.

As far as I know the point of the library is to use only internal classes/structs without any dependencies. So, std::vector is nowhere used in the code. Only internal clases/structs are allowed.

What would you suggest to use instead of internal::Array<bool> parsedFaces; ? Typically, a boolean is represented as 1 byte (8 bits). Is there something less weighter?

I'll fix the typo.

@castano about your latest post:

1 About the green chart 52: This overlap (on your picture) is exaclty the LSCM unwrapping which doesn't count complex charts. This is an expected behaviour when we have smooth/round shapes like a subdivided monkey. The computeBoundaryIntersection() will not fix this issue as it has a simple/primitive process which serves for a different purpose (I'll explain below). This is a common behaviour for such smooth models.

2 As far as I get the computeBoundaryIntersection() function compares Chart1 and Chart2 and intersects their overlapped polygons to Chart3. Did I get it right?
image

3 It seems you tested my model with not default parameters of ChartOption. Please use default ChartOption and set computeBoundaryIntersection=true. Then you will see gaps/holes like this:
image
image

4 About a separate PR: unfortunately, quads and ngons depend on the computeBoundaryIntersection parameter. The computeBoundaryIntersection concerns them directly because it breaks them. So, it should be all in one PR.
image
image

@mifth
Copy link
Author

mifth commented Nov 5, 2024

@castano I checked out the computeBoundaryIntersection() function again. You are right. The function tries to remove intersected faces of a uv map. It works per mesh. But it looks like its pretty complicated...

@mifth
Copy link
Author

mifth commented Nov 5, 2024

@castano I'm looking at the issue further. It seems the problem is not with computeBoundaryIntersection.
m_isInvalid affects this issue. I've been investigating the issue further.

image

@mifth
Copy link
Author

mifth commented Nov 5, 2024

It seems it's somewhere there:
image

@mifth
Copy link
Author

mifth commented Nov 5, 2024

Hi @castano @siliconvoodoo it seems I was able to fix the issue with my latest commit. A problem was in this commented code:
image

@mifth
Copy link
Author

mifth commented Nov 5, 2024

Here is a video with my creepy explanation:
https://youtu.be/FBvfjz8ciHA

@mifth
Copy link
Author

mifth commented Nov 5, 2024

Just some screenshots of quads and triangles:
image
image

image
image
image

I'm very happy with the result!

Comment on lines 6904 to 6905
if (m_faceInAnyPatch.get(oface))
continue;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just this part if @jpcy can give an opinion he'd be the most relevant person for analysis.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@siliconvoodoo yeah, I understand your concern. I've added this check because a triangle/face can be added multiple times to an array. But sure, @jpcy knows better if it makes sense.

m_patch.push_back(face);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies I've deleted my last comment because there were different checks.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right! I'll delete this check with a new commit.
image

@siliconvoodoo
Copy link

siliconvoodoo commented Nov 6, 2024

I merged your changes locally and tested on some of my scenes with no particular adverse of negative behaviors compared to original master. (edit: still need to check again with last commits)

@mifth
Copy link
Author

mifth commented Nov 6, 2024

I merged your changes locally and tested on some of my scenes with no particular adverse of negative behaviors compared to original master. (edit: still need to check again with last commits)

Thanks a lot. There are no any big changes for triangulated meshes. Have you tried meshes which have quads/ngons?

@mifth
Copy link
Author

mifth commented Nov 6, 2024

I've tested 2 versions of monkeys. With quads and with triangles.
Quads: 1.37sec, 31000 quads.
Triangles: 2.2sec, 62000 triangles.
image

@mifth
Copy link
Author

mifth commented Nov 6, 2024

And another one test. I made the same amount of quads(duplicated monkeys one time) and the same amount of triangles.

Quads: 1.44sec, 62000 quads.
Triangles: 2.2sec, 62000 triangles.

image

It looks pretty cool and means that my work for quads and ngons was done pretty well.
But I can't test memory. I guess the Quads version will take more memory.

@mifth
Copy link
Author

mifth commented Nov 7, 2024

I've removed "#IF 0" fix and will make it as a separate PR as @castano suggested. The Quads/NGons don't depend on it after removing the computeBoundaryIntersection variable.

@mifth
Copy link
Author

mifth commented Nov 7, 2024

New pull request is here #141

mifth added 3 commits November 7, 2024 22:57
… leave it commented to make an option in future.
…s/NGons and I wasn't be able to fix it. So I commented my fixes in the PiecewiseParam::computeChart() function and set "m_isInvalid" to work only for Triangles. I hope someone will fix the PiecewiseParam::computeChart() function in future.
@mifth
Copy link
Author

mifth commented Nov 8, 2024

Hi all,

I've made commit here: 2f47d81

Unfortunately, the PiecewiseParam::computeChart() function still makes artifacts for Quads/NGons so I had to switch it off. The code is designed for triangles only and I failed to fix this part. I hope someone will fix the PiecewiseParam::computeChart() function in future.

Without the the PiecewiseParam::computeChart() function all still works well.

@mifth
Copy link
Author

mifth commented Nov 9, 2024

Update: I uncommented code for flipped polygons only:
a4bb139

@siliconvoodoo
Copy link

I was going to ask if it wouldn't be simpler to triangulate first then go through triangle parameterization. But I recalled you're doing a blender plugin so you need to preserve the original geometry as much as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants