Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Try out tessellating polygons #49

Merged
merged 13 commits into from
Mar 3, 2014
Merged

Try out tessellating polygons #49

merged 13 commits into from
Mar 3, 2014

Conversation

kkaefer
Copy link
Contributor

@kkaefer kkaefer commented Feb 17, 2014

We should try out tessellating polygons with e.g. https://github.com/memononen/libtess2 rather than using the stencil buffer approach. Note that this is a big deviation from the way we're drawing polygons with WebGL and that this might introduce differences in rendering.

@incanus
Copy link
Contributor

incanus commented Feb 7, 2014

Why take this approach? Just curious.

@ansis
Copy link
Contributor

ansis commented Feb 7, 2014

We could take this approach with webgl too. mapbox/mapbox-gl-js#229

The main possible advantages I'm seeing are

  • not using the stencil buffer
  • less fragments to shade since no fragments get clipped by the stencil buffer
  • 1-2 draw calls instead of 3

but @kkaefer might be thinking something else

Side question:

Theoretically, we could draw fills + antialiasing in one draw call, right?
Each vertex had the distance to the opposite edge and the number of that vertex (0, 1, or 2). That should fit into 2 bytes per vertex. The vertex shader sets three varying floats: two to zero and one to the distance for the opposite edge. Each fragment should then have the distance to all three edges and could fade accordingly. Some special value could be used to prevent fading for internal edges.

@incanus
Copy link
Contributor

incanus commented Feb 7, 2014

  • not using the stencil buffer
  • less fragments to shade since no fragments get clipped by the stencil buffer

Nice, this is helpful. I'm still pretty fresh to performance considerations but this makes sense.

@ansis
Copy link
Contributor

ansis commented Feb 7, 2014

I just want to add that its completely a guess, I have no idea whether it is actually significant.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 13, 2014

@ansis While we could probably get this to work, the major drawback of that approach is that we couldn't share vertices across triangles because they have the fade distance encoded. It's probably easier to use two draw calls: One to render the triangle strips (and stencil buffer if needed), and one to render the outline (using the stencil buffer to knock out if needed).

We're still going to need a stencil buffer, for (a) clipping to tile boundary and (b) clipping outline to only render outside of the polygon. The benefit we're going to get is that we have fewer fragments to shade when drawing the initial stencil buffer because we have no overlapping triangles fans anymore.

@ansis
Copy link
Contributor

ansis commented Feb 13, 2014

Yeah, that makes sense.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

Triangulation works, but is pretty slow. Typical tessellation times for a tile with many buildings is 1-2 seconds, which makes the app feel slow because tiles take more time to load.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

Trying different approaches. This is putting all fills in one bucket into one triangulation:

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

This is what I'm getting if we try to tessellate every feature by itself:

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

My conclusion is that tessellating smaller batches could be a lot faster, but it currently is a lot slower because of memory allocation overhead. libtess2 provides a memory allocation interface, so we could use a memory pool to handle the many small allocations.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

I'm not too sure about the performance wins here. On iPhone 4, I'm seeing a speed increase of about 30-40% (from 22 to 30 fps), but on iPad 2, we're already at 60 fps. Might be interesting to try this on iPad 3/4 where we have a lot more fragments to shade.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

3843bf1 changes the allocator defaults and gives much better tessellation performance, but loading tiles feels still a little slower than before.

@incanus
Copy link
Contributor

incanus commented Feb 17, 2014

Might be interesting to try this on iPad 3/4 where we have a lot more fragments to shade.

I can benchmark this today.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 17, 2014

Also, this might benefit from another allocator like tcmalloc.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

https://code.google.com/p/poly2tri/ might also be interesting, but this project uses delaunay triangulation which inserts additional (steiner) points, which we don't need for rendering.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

We should revisit putting tessellation into vector tiles.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

Currently, we're tessellating twice: Once to obtain the outlines with positive winding, then we use that output an feed it back into the tessellation library to get the list of triangles that we need to render the fill. Then we're doing a reverse mapping of indices and use the previous indices (from the outline). Since tessellation might introduce new indices, this can fail (see 004ff9e). It'd be better if we generated this in one go because it'd reduce the tessellation calls by half.

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

The good part about this is that we now properly overlap partially translucent buildings. The bad part is that they will only have antialiased outlines, there won't be any antialiasing where they overlap.

Before:

After:

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

There are still seam issues: http://i.kkaefer.com/h7696.png

@kkaefer
Copy link
Contributor Author

kkaefer commented Feb 18, 2014

The seams seem to be in the data, so nothing related to this PR.

Conflicts:
	include/llmr/renderer/fill_bucket.hpp
	src/renderer/fill_bucket.cpp
	src/renderer/painter.cpp
kkaefer added a commit that referenced this pull request Mar 3, 2014
Try out tessellating polygons
@kkaefer kkaefer merged commit 2e0681e into master Mar 3, 2014
@kkaefer kkaefer deleted the tessellation branch March 3, 2014 14:08
@ljbade
Copy link
Contributor

ljbade commented Jun 17, 2014

Curious as to why you use libtess2 vs poly2tri?

Poly2tri generates larger triangles so is more efficient due to less vertices. Also prevents lots of tiny triangles that slow down rendering.

Poly2tri uses constrained delaunay triangulation which does not insert steiner points. It only uses the existing polygon vertices.

Poly2tri is fast and stable. I have personally tested it with massive (1000s vertices) polygons with 100s of nested holes.

Never had it crash or produce incorrect rendering.

@kkaefer
Copy link
Contributor Author

kkaefer commented Jun 17, 2014

@ljbade I tried poly2tri, but I got a few crashes from it. They recommend using ClipperLib with it, which I'm not sure I did back then. We may move to poly2tri eventually, but the current focus is on getting the library more stable.

@ljbade
Copy link
Contributor

ljbade commented Jun 17, 2014

Interesting you found some crashes in poly2tri.

Makes sense to keep it stable for the moment, but GLU tessellation ain't pretty.

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

Successfully merging this pull request may close these issues.

4 participants