Add existing to tracked
This commit is contained in:
+178
@@ -0,0 +1,178 @@
|
||||
uniform highp sampler2D u_vectorSegmentTexture;
|
||||
uniform highp sampler2D u_vectorWidthTexture;
|
||||
uniform highp sampler2D u_vectorColorTexture;
|
||||
uniform highp sampler2D u_vectorSegmentPrimitiveIndicesTexture;
|
||||
uniform highp sampler2D u_vectorGridCellIndicesTexture;
|
||||
uniform highp sampler2D u_vectorPolygonEdgeTexture;
|
||||
uniform highp sampler2D u_vectorPolygonEdgePrimitiveIndicesTexture;
|
||||
uniform highp sampler2D u_vectorPolygonGridCellIndicesTexture;
|
||||
|
||||
// UV-space offset from the closest point on the segment to p.
|
||||
vec2 vectorOffsetToLine(vec2 p, vec4 line)
|
||||
{
|
||||
vec2 a = line.xy;
|
||||
vec2 b = line.zw;
|
||||
vec2 ab = b - a;
|
||||
float abLengthSquared = dot(ab, ab);
|
||||
if (abLengthSquared < 1.0e-8)
|
||||
{
|
||||
return p - a;
|
||||
}
|
||||
float t = clamp(dot(p - a, ab) / abLengthSquared, 0.0, 1.0);
|
||||
return p - (a + t * ab);
|
||||
}
|
||||
|
||||
ivec2 vectorIndexToUv(int index, ivec2 size)
|
||||
{
|
||||
int v = index / size.x;
|
||||
int u = index - v * size.x;
|
||||
return ivec2(u, v);
|
||||
}
|
||||
|
||||
// Drape clamped vector polylines onto the terrain surface. The fragment's
|
||||
// tile UV picks a grid cell, then only that cell's line segments (packed in
|
||||
// tile-local UV space) are tested for proximity. Within the line width, the
|
||||
// vector color is alpha-composited over the terrain (no discard).
|
||||
vec4 vectorPolylineRender(vec2 vectorUv, vec4 baseColor)
|
||||
{
|
||||
// A tile without polylines binds a 1x1 placeholder; a real grid header
|
||||
// [gridWidth, gridHeight, ...] is at least 3 texels.
|
||||
ivec2 headerSize = textureSize(u_vectorGridCellIndicesTexture, 0);
|
||||
if (headerSize.x * headerSize.y < 3)
|
||||
{
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
// Inverse UV-per-pixel Jacobian: measures line distance in screen pixels so
|
||||
// width stays constant under anisotropic (oblique) foreshortening.
|
||||
mat2 screenFromUv = inverse(mat2(dFdx(vectorUv), dFdy(vectorUv)));
|
||||
int gridWidth = int(texelFetch(u_vectorGridCellIndicesTexture, vectorIndexToUv(0, headerSize), 0).r);
|
||||
int gridHeight = int(texelFetch(u_vectorGridCellIndicesTexture, vectorIndexToUv(1, headerSize), 0).r);
|
||||
int cellX = clamp(int(vectorUv.x * float(gridWidth)), 0, gridWidth - 1);
|
||||
int cellY = clamp(int(vectorUv.y * float(gridHeight)), 0, gridHeight - 1);
|
||||
int cellIndex = cellX + cellY * gridWidth;
|
||||
|
||||
// Cell end offsets follow the two gridWidth/gridHeight texels, so cell
|
||||
// N's end is at texel N + 2. A cell's start is the previous cell's end
|
||||
// (texel N + 1); cell 0's start is implicitly 0.
|
||||
int indexEnd = int(texelFetch(u_vectorGridCellIndicesTexture, vectorIndexToUv(cellIndex + 2, headerSize), 0).r);
|
||||
int indexStart = cellIndex == 0
|
||||
? 0
|
||||
: int(texelFetch(u_vectorGridCellIndicesTexture, vectorIndexToUv(cellIndex + 1, headerSize), 0).r);
|
||||
|
||||
ivec2 segmentTextureSize = textureSize(u_vectorSegmentTexture, 0);
|
||||
ivec2 primitiveTextureSize = textureSize(u_vectorWidthTexture, 0);
|
||||
|
||||
for (int i = indexStart; i < indexEnd; i++)
|
||||
{
|
||||
ivec2 segmentUv = vectorIndexToUv(i, segmentTextureSize);
|
||||
vec4 segment = texelFetch(u_vectorSegmentTexture, segmentUv, 0);
|
||||
|
||||
int primitiveIndex = int(texelFetch(u_vectorSegmentPrimitiveIndicesTexture, segmentUv, 0).r);
|
||||
ivec2 primitiveUv = vectorIndexToUv(primitiveIndex, primitiveTextureSize);
|
||||
|
||||
float lineWidth = texelFetch(u_vectorWidthTexture, primitiveUv, 0).r * 255.0;
|
||||
|
||||
vec2 offsetUv = vectorOffsetToLine(vectorUv, segment);
|
||||
if (length(screenFromUv * offsetUv) < lineWidth)
|
||||
{
|
||||
// Alpha-composite vector over terrain.
|
||||
vec4 vectorColor = texelFetch(u_vectorColorTexture, primitiveUv, 0);
|
||||
baseColor = vectorColor * vec4(vectorColor.aaa, 1.0) + baseColor * (1.0 - vectorColor.a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
// Composites a polygon's fill over baseColor when the pixel is inside it. A
|
||||
// negative index (empty cell or first iteration) or an outside pixel is a
|
||||
// no-op.
|
||||
vec4 vectorCompositePolygonFill(vec4 baseColor, int primitiveIndex, bool inside, ivec2 primitiveTextureSize)
|
||||
{
|
||||
if (!inside || primitiveIndex < 0)
|
||||
{
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
ivec2 primitiveUv = vectorIndexToUv(primitiveIndex, primitiveTextureSize);
|
||||
vec4 fillColor = texelFetch(u_vectorColorTexture, primitiveUv, 0);
|
||||
return fillColor * vec4(fillColor.aaa, 1.0) + baseColor * (1.0 - fillColor.a);
|
||||
}
|
||||
|
||||
// True if a horizontal +x ray from p crosses the edge. The half-open interval
|
||||
// (> vs <=) counts a ray through a shared vertex exactly once.
|
||||
bool vectorEdgeCrossesRay(vec4 edge, vec2 p)
|
||||
{
|
||||
if ((edge.y > p.y) == (edge.w > p.y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float t = (p.y - edge.y) / (edge.w - edge.y);
|
||||
float xIntersect = edge.x + t * (edge.z - edge.x);
|
||||
return p.x < xIntersect;
|
||||
}
|
||||
|
||||
// Drape clamped vector polygon fills onto the terrain surface. The fragment's
|
||||
// tile UV picks a grid cell whose edges were clipped to the cell on the CPU,
|
||||
// forming closed loops, so an even-odd horizontal ray cast within the cell
|
||||
// decides coverage. Edges arrive grouped by primitive; each covering
|
||||
// primitive's fill color is alpha-composited in primitive order (no discard).
|
||||
vec4 vectorPolygonRender(vec2 vectorUv, vec4 baseColor)
|
||||
{
|
||||
// A tile without polygons binds a 1x1 placeholder; a real grid header
|
||||
// [gridWidth, gridHeight, ...] is at least 3 texels.
|
||||
ivec2 headerSize = textureSize(u_vectorPolygonGridCellIndicesTexture, 0);
|
||||
if (headerSize.x * headerSize.y < 3)
|
||||
{
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
int gridWidth = int(texelFetch(u_vectorPolygonGridCellIndicesTexture, vectorIndexToUv(0, headerSize), 0).r);
|
||||
int gridHeight = int(texelFetch(u_vectorPolygonGridCellIndicesTexture, vectorIndexToUv(1, headerSize), 0).r);
|
||||
int cellX = clamp(int(vectorUv.x * float(gridWidth)), 0, gridWidth - 1);
|
||||
int cellY = clamp(int(vectorUv.y * float(gridHeight)), 0, gridHeight - 1);
|
||||
int cellIndex = cellX + cellY * gridWidth;
|
||||
|
||||
// Cell end offsets follow the two gridWidth/gridHeight texels, so cell
|
||||
// N's end is at texel N + 2. A cell's start is the previous cell's end
|
||||
// (texel N + 1); cell 0's start is implicitly 0.
|
||||
int indexEnd = int(texelFetch(u_vectorPolygonGridCellIndicesTexture, vectorIndexToUv(cellIndex + 2, headerSize), 0).r);
|
||||
int indexStart = cellIndex == 0
|
||||
? 0
|
||||
: int(texelFetch(u_vectorPolygonGridCellIndicesTexture, vectorIndexToUv(cellIndex + 1, headerSize), 0).r);
|
||||
|
||||
ivec2 edgeTextureSize = textureSize(u_vectorPolygonEdgeTexture, 0);
|
||||
ivec2 primitiveTextureSize = textureSize(u_vectorColorTexture, 0);
|
||||
|
||||
int currentPrimitive = -1;
|
||||
bool inside = false;
|
||||
|
||||
for (int i = indexStart; i < indexEnd; i++)
|
||||
{
|
||||
ivec2 edgeUv = vectorIndexToUv(i, edgeTextureSize);
|
||||
vec4 edge = texelFetch(u_vectorPolygonEdgeTexture, edgeUv, 0);
|
||||
int primitiveIndex = int(texelFetch(u_vectorPolygonEdgePrimitiveIndicesTexture, edgeUv, 0).r);
|
||||
|
||||
// A new primitive means the previous group is complete: composite it,
|
||||
// then start counting the new one fresh.
|
||||
if (primitiveIndex != currentPrimitive)
|
||||
{
|
||||
baseColor = vectorCompositePolygonFill(baseColor, currentPrimitive, inside, primitiveTextureSize);
|
||||
currentPrimitive = primitiveIndex;
|
||||
inside = false;
|
||||
}
|
||||
|
||||
if (vectorEdgeCrossesRay(edge, vectorUv))
|
||||
{
|
||||
inside = !inside;
|
||||
}
|
||||
}
|
||||
|
||||
// The last primitive group has no trailing edge to trigger its composite.
|
||||
baseColor = vectorCompositePolygonFill(baseColor, currentPrimitive, inside, primitiveTextureSize);
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
Reference in New Issue
Block a user