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

sw_engine: Fix one pixel blank #1342

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft

Conversation

RuiwenTang
Copy link
Collaborator

This PR fix #1329

If pixel covered by two edge with same slope with different direction. The area value is zero, but the winding number is not.

@hermet hermet added the enhancement Improve features label Apr 1, 2023
@hermet
Copy link
Member

hermet commented Apr 1, 2023

@RuiwenTang thanks for your patch.

I think enhancing this feature may be a bit more complex because the current TVG renderer handles closed shapes with separate drawing units, which is different from the triangle-list mesh composition in OpenGL and D3D. As a result, there may be visible anti-aliasing gaps between the shapes, especially in a rotated version (see the following figure). I've considered a proper and efficient model to handle this, but it's not clear yet. Perhaps the TVG canvas could merge the closed shapes into one paint before moving on to rendering, although this may not be efficient for general cases. Instead, I would suggest that users request a single rectangle directly, as it would be much cheaper! Any opinions?

shot-2023-04-02_00-42-42

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Apr 2, 2023

Yes, this problem is more complicated than I thought, I prefer merge these closed pathes. I'm going to dig a little deeper into this issue

@hermet
Copy link
Member

hermet commented Apr 3, 2023

@RuiwenTang I mentioned earlier that we need the shapes-merge step prior to the rasterization stage(Sure, you can suggest another solution). If we include this fix, it could become redundant. I don't want to leave any dead code that will be difficult to maintain in the future. The problem is that if we change the height of the box (triangles), the patch won't work, as shown in the attached figure. This could confuse users and make them think it's a bug, which would hurt the consistency of the behavior. Currently, on the other hand, we don't support merged shapes. However, if you say that this fix is REALLY necessary for your project now, we can discuss further and compromise for the quick-fix.

thorvg

@RuiwenTang
Copy link
Collaborator Author

Ok,and currently I am working on merge these closed shapes. I have implemented a similar algorithm before in my local project.

@RuiwenTang RuiwenTang marked this pull request as draft April 3, 2023 13:10
@hermet
Copy link
Member

hermet commented Apr 17, 2023

we have the merging shapes function in b26672a

@RuiwenTang
Copy link
Collaborator Author

@hermet I pushed a sweep line algorithm. I used this algorithm in my own engine to do polygon triangulation and complex polygon clip. I hope this code can help to fix this case.
The result is showing below, the outline is rendered on second column:

the one pixel blank case I wish to fix:

image

Path with intersection:

image

Path with intersection and different filltype

image
image

@RuiwenTang
Copy link
Collaborator Author

RuiwenTang commented Apr 23, 2023

Here is a sample code:

std::array<std::unique_ptr<tvg::Shape>, 2> gen_shape() {
  std::array<std::unique_ptr<tvg::Shape>, 2> ret{};

  // stroke
  ret[0] = tvg::Shape::gen();
  ret[0]->moveTo(100, 10);
  ret[0]->lineTo(40, 180);
  ret[0]->lineTo(190, 60);
  ret[0]->lineTo(10, 60);
  ret[0]->lineTo(160, 180);
  ret[0]->fill(tvg::FillRule::EvenOdd);
  ret[0]->close();
  ret[0]->stroke(0, 255, 0, 255);
  ret[0]->stroke(3.f);
  // fill
  ret[1] = tvg::Shape::gen();
  ret[1]->moveTo(100, 10);
  ret[1]->lineTo(40, 180);
  ret[1]->lineTo(190, 60);
  ret[1]->lineTo(10, 60);
  ret[1]->lineTo(160, 180);
  ret[1]->close();
  ret[1]->fill(0, 255, 0, 255);
  ret[1]->fill(tvg::FillRule::EvenOdd);

  return ret;
};

auto paths = gen_shape();


  auto outline = paths[0]->extractOutline();

  outline->translate(200, 100);
  outline->stroke(0, 255, 0, 255);
  outline->stroke(3.f);

  canvas->push(std::move(paths[0]));

  paths[1]->translate(0, 200);

  canvas->push(std::move(paths[1]));

  canvas->push(std::move(outline));

@hermet
Copy link
Member

hermet commented Apr 24, 2023

Thank you, @RuiwenTang, for your contribution.

  1. ThorVG can apply this feature after the v0.9 release.
  2. Could you provide more information about the algorithm you applied here? Do you have any reference links or sources for the code? We would like to double-check for any licensing issues.
  3. I believe this change will require a significant amount of polishing to be smoothly integrated into the ThorVG source code. If you are interested, we could go through additional review stages. Otherwise, you can leave it to us.

Again thanks, you did really good job.

@hermet hermet added the feature New feature additions label Apr 24, 2023
@RuiwenTang
Copy link
Collaborator Author

The basic scanline idea comes from this video: https://www.youtube.com/watch?v=qkhUNzCGDt0&t=293s .

Some data struct and geometric calculation in this code is inspired by SKIA: https://github.com/google/skia/blob/main/src/gpu/ganesh/geometry/GrTriangulator.cpp
Under BSD-3 license.

I made a lot of changes to make the code simple and can do more things like extract the boundary or do advance polygon boolean operation. I can share these changes if thorvg needs these feature.

If two sub path sharing one edge but with different direction.
The winding number of this edge is not zero, but the alpha for aa may be
zero. Since this edge is inside whole polygon, need to mark this edge in sweep
line based on this edge's cover.
@RuiwenTang
Copy link
Collaborator Author

image
take some time to rebase my branch and test the curve case :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improve features feature New feature additions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrect fill result when two sub path sharing one edge but has different direction or winding number
2 participants