Choose the antimeridian world copy per tile, and clip a tile to itself - #7
Merged
Merged
Conversation
Wide views rendered as horizontal bands stretched across the map, in area fills and lines. Each vertex stage computed world.x = p.x + rint(wrap_x - p.x), which places a vertex at the world copy nearest the camera. That rule dates from tile-local geometry, where p.x spans one tile and every vertex of a tile gets the same result. The renderer builds one scene against one origin, so p.x spans the whole view and the result changes halfway across. A triangle lying over the half-world seam ended up with corners a whole world apart. Six corners of a quad share one anchor, so label quads were unaffected. Camera.placeTileX picks the copy by the tile's centre. Camera.wrappedCopy names the second copy when the view is wide enough to see both, from around z1 down, and the tile is then listed and placed twice. Camera.mvpOrigin wraps the origin-to-camera delta in x, so a camera that crossed the antimeridian since the scene was built moves the whole scene at once. The vertex stages now only project. Uniforms keeps wrap_x as a reserved field to hold the block at 128 bytes.
charttable's vertex stages placed each vertex at the world copy nearest the camera, and wanted that offset stated beside the MVP. Applied per vertex it split any primitive lying across the half-world seam, so the choice moved to the host, per tile and per scene. Camera.mvpOrigin, which the overlay already builds its MVP with, wraps the x delta itself. The wrap_x field is gone from Uniforms.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wide views of a style rendered as horizontal bands stretched across the map, in area fills and lines. Each vertex stage placed a vertex at the world copy nearest the camera with
world.x = p.x + rint(wrap_x - p.x). That rule dates from tile-local geometry, wherep.xspans one tile and every vertex of a tile gets the same result. The renderer builds one scene against one origin, sop.xspans the whole view and the result changes halfway across it. At z2 centred on lon -95, a probe over the concatenated scene measured vertex x from -0.4910 to 0.5188 and 86 triangles whose corners fall on different copies. Six corners of a quad share one anchor, so label quads were unaffected.Camera.placeTileXpicks the copy by the tile's centre.Camera.wrappedCopynames the second copy when the view is wide enough to see both, from around z1 down, and the tile is then listed and placed twice.Camera.mvpOriginwraps the origin-to-camera delta in x, so a camera that crossed the antimeridian since the scene was built moves the whole scene at once. The vertex stages only project.The second commit is a separate defect at the same seam between what DESIGN.md describes and what the renderer does. A translucent fill drew the tile grid into the map as a lattice of darker strips, about 14 px wide at z6, with a darker square where two crossed, and grey hairlines either side of every boundary. An MVT tile holds its features clipped to its own bounds plus an overhang, so two neighbours both hold the strip along the edge they share. Rendering
land-forestalone (fill-opacity: 0.1) at z5.8 gave four colours: the background, the fill once, the fill twice, and the fill three times where two strips cross. The outline the clipper leaves along the buffer's own edge is a linestring, and a line layer strokes it, which drew the hairlines.The overhang stays in the geometry, because a line's joins and caps are built from it, and the draw trims it instead. Each triangle range holds the bounds of its tile in the scene frame, and the fragment stage drops fragments outside them. The test is in world space because a scissor rect cannot express a tile under a rotated view. The vertex stage passes the fragment stage the position its fragments cover, the vertex position plus its screen-space offset converted to world units, so a wide line is clipped along its stroke.
Uniformsgrows to 144 bytes forclip_rect, withworld_per_pxin the slot the retired per-vertex wrap left.The clip joins the batcher's merge key. The draw count for the reference view is 180 with and without it, because parts concatenate tile-major and one layer's ranges from two tiles were already separated by the contiguity test. Frame times over three runs of the zoom benchmark are p50 0.07 ms and p95 around 1.0 ms either way.
Rendering
land-forestalone after the change gives two colours. A pixel diff of a line-only render at the same view removes 1550 pixels and adds none, 1504 of them within 12 px of a tile edge and concentrated in two columns of 640 and 625 pixels at the buffer boundaries, which are the hairlines. Line work stays continuous across every boundary, and a 35 degree rotated view of the same place shows no lattice.zig buildandzig build testpass, 233 tests with 18 skipped. Spec conformance is 575/577, the same two output failures as the base. The Vulkan.spvartifacts are rebuilt with glslangValidator and checked with spirv-val. The Vulkan and D3D12 changes are compiled but not run: this machine renders through Metal.