#version 300 es precision mediump float; layout(std140)uniform Uniforms{ float startTimestamp; // Unix 时间戳开始 float endTimestamp; // Unix 时间戳结束 float currentTimestamp; // 当前时间戳 float radius; float d; float timelineStartX; // 时间轴在屏幕上的开始X坐标 float timelineEndX; // 时间轴在屏幕上的结束X坐标 float padding1; // 填充以对齐到8字节边界 vec2 viewportSize; float zoomLevel; // 当前缩放级别 float panOffset; // 当前平移偏移 }; struct Instant{ vec2 position; vec4 color; }; in Instant i_instant; out vec4 FragColor; float sdVesica(vec2 p,float r,float d) { p=abs(p); float b=sqrt(r*r-d*d);// can delay this sqrt by rewriting the comparison return((p.y-b)*d>p.x*b)?length(p-vec2(0.,b))*sign(d) :length(p-vec2(-d,0.))-r; } void main(){ // 从实例数据中获取时间戳(存储在position.x中)和Y坐标(存储在position.y中) float timestamp = i_instant.position.x; float centerY = i_instant.position.y; // 计算时间戳在时间轴范围内的相对位置(0-1) float timeProgress = (timestamp - startTimestamp) / (endTimestamp - startTimestamp); // 考虑缩放和平移,计算屏幕X坐标 float timelineWidth = timelineEndX - timelineStartX; float scaledTimelineWidth = timelineWidth * zoomLevel; float screenX = timelineStartX + panOffset + timeProgress * scaledTimelineWidth; // 如果vesica在屏幕外,提前丢弃 if (screenX < -radius*2.0 || screenX > viewportSize.x + radius*2.0) { discard; } // 计算vesica在屏幕上的实际位置 vec2 vesicaCenter = vec2(screenX, centerY); vec2 p = gl_FragCoord.xy - vesicaCenter; float sdf = sdVesica(p, radius, d); // 使用fwidth计算像素梯度,实现自适应反锯齿 float fw = fwidth(sdf); // 在高分屏下增强反锯齿效果 (可根据需要调整系数) float aaWidth = max(fw, 0.5); // 确保最小反锯齿宽度 // 使用smoothstep创建平滑边缘,aaWidth控制反锯齿宽度 float alpha = 1.0 - smoothstep(-aaWidth, aaWidth, sdf); // 如果完全透明就丢弃片段以提高性能 if (alpha < 0.001) { discard; } // 使用实例颜色并应用计算出的alpha vec3 color = i_instant.color.rgb; FragColor = vec4(color, alpha * i_instant.color.a); }