PolylineCommon.glsl 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. void clipLineSegmentToNearPlane(
  2. vec3 p0,
  3. vec3 p1,
  4. out vec4 positionWC,
  5. out bool clipped,
  6. out bool culledByNearPlane,
  7. out vec4 clippedPositionEC)
  8. {
  9. culledByNearPlane = false;
  10. clipped = false;
  11. vec3 p0ToP1 = p1 - p0;
  12. float magnitude = length(p0ToP1);
  13. vec3 direction = normalize(p0ToP1);
  14. // Distance that p0 is behind the near plane. Negative means p0 is
  15. // in front of the near plane.
  16. float endPoint0Distance = czm_currentFrustum.x + p0.z;
  17. // Camera looks down -Z.
  18. // When moving a point along +Z: LESS VISIBLE
  19. // * Points in front of the camera move closer to the camera.
  20. // * Points behind the camrea move farther away from the camera.
  21. // When moving a point along -Z: MORE VISIBLE
  22. // * Points in front of the camera move farther away from the camera.
  23. // * Points behind the camera move closer to the camera.
  24. // Positive denominator: -Z, becoming more visible
  25. // Negative denominator: +Z, becoming less visible
  26. // Nearly zero: parallel to near plane
  27. float denominator = -direction.z;
  28. if (endPoint0Distance > 0.0 && abs(denominator) < czm_epsilon7)
  29. {
  30. // p0 is behind the near plane and the line to p1 is nearly parallel to
  31. // the near plane, so cull the segment completely.
  32. culledByNearPlane = true;
  33. }
  34. else if (endPoint0Distance > 0.0)
  35. {
  36. // p0 is behind the near plane, and the line to p1 is moving distinctly
  37. // toward or away from it.
  38. // t = (-plane distance - dot(plane normal, ray origin)) / dot(plane normal, ray direction)
  39. float t = endPoint0Distance / denominator;
  40. if (t < 0.0 || t > magnitude)
  41. {
  42. // Near plane intersection is not between the two points.
  43. // We already confirmed p0 is behind the naer plane, so now
  44. // we know the entire segment is behind it.
  45. culledByNearPlane = true;
  46. }
  47. else
  48. {
  49. // Segment crosses the near plane, update p0 to lie exactly on it.
  50. p0 = p0 + t * direction;
  51. // Numerical noise might put us a bit on the wrong side of the near plane.
  52. // Don't let that happen.
  53. p0.z = min(p0.z, -czm_currentFrustum.x);
  54. clipped = true;
  55. }
  56. }
  57. clippedPositionEC = vec4(p0, 1.0);
  58. positionWC = czm_eyeToWindowCoordinates(clippedPositionEC);
  59. }
  60. vec4 getPolylineWindowCoordinatesEC(vec4 positionEC, vec4 prevEC, vec4 nextEC, float expandDirection, float width, bool usePrevious, out float angle)
  61. {
  62. // expandDirection +1 is to the _left_ when looking from positionEC toward nextEC.
  63. #ifdef POLYLINE_DASH
  64. // Compute the window coordinates of the points.
  65. vec4 positionWindow = czm_eyeToWindowCoordinates(positionEC);
  66. vec4 previousWindow = czm_eyeToWindowCoordinates(prevEC);
  67. vec4 nextWindow = czm_eyeToWindowCoordinates(nextEC);
  68. // Determine the relative screen space direction of the line.
  69. vec2 lineDir;
  70. if (usePrevious) {
  71. lineDir = normalize(positionWindow.xy - previousWindow.xy);
  72. }
  73. else {
  74. lineDir = normalize(nextWindow.xy - positionWindow.xy);
  75. }
  76. angle = atan(lineDir.x, lineDir.y) - 1.570796327; // precomputed atan(1,0)
  77. // Quantize the angle so it doesn't change rapidly between segments.
  78. angle = floor(angle / czm_piOverFour + 0.5) * czm_piOverFour;
  79. #endif
  80. vec4 clippedPrevWC, clippedPrevEC;
  81. bool prevSegmentClipped, prevSegmentCulled;
  82. clipLineSegmentToNearPlane(prevEC.xyz, positionEC.xyz, clippedPrevWC, prevSegmentClipped, prevSegmentCulled, clippedPrevEC);
  83. vec4 clippedNextWC, clippedNextEC;
  84. bool nextSegmentClipped, nextSegmentCulled;
  85. clipLineSegmentToNearPlane(nextEC.xyz, positionEC.xyz, clippedNextWC, nextSegmentClipped, nextSegmentCulled, clippedNextEC);
  86. bool segmentClipped, segmentCulled;
  87. vec4 clippedPositionWC, clippedPositionEC;
  88. clipLineSegmentToNearPlane(positionEC.xyz, usePrevious ? prevEC.xyz : nextEC.xyz, clippedPositionWC, segmentClipped, segmentCulled, clippedPositionEC);
  89. if (segmentCulled)
  90. {
  91. return vec4(0.0, 0.0, 0.0, 1.0);
  92. }
  93. vec2 directionToPrevWC = normalize(clippedPrevWC.xy - clippedPositionWC.xy);
  94. vec2 directionToNextWC = normalize(clippedNextWC.xy - clippedPositionWC.xy);
  95. // If a segment was culled, we can't use the corresponding direction
  96. // computed above. We should never see both of these be true without
  97. // `segmentCulled` above also being true.
  98. if (prevSegmentCulled)
  99. {
  100. directionToPrevWC = -directionToNextWC;
  101. }
  102. else if (nextSegmentCulled)
  103. {
  104. directionToNextWC = -directionToPrevWC;
  105. }
  106. vec2 thisSegmentForwardWC, otherSegmentForwardWC;
  107. if (usePrevious)
  108. {
  109. thisSegmentForwardWC = -directionToPrevWC;
  110. otherSegmentForwardWC = directionToNextWC;
  111. }
  112. else
  113. {
  114. thisSegmentForwardWC = directionToNextWC;
  115. otherSegmentForwardWC = -directionToPrevWC;
  116. }
  117. vec2 thisSegmentLeftWC = vec2(-thisSegmentForwardWC.y, thisSegmentForwardWC.x);
  118. vec2 leftWC = thisSegmentLeftWC;
  119. float expandWidth = width * 0.5;
  120. // When lines are split at the anti-meridian, the position may be at the
  121. // same location as the next or previous position, and we need to handle
  122. // that to avoid producing NaNs.
  123. if (!czm_equalsEpsilon(prevEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1) && !czm_equalsEpsilon(nextEC.xyz - positionEC.xyz, vec3(0.0), czm_epsilon1))
  124. {
  125. vec2 otherSegmentLeftWC = vec2(-otherSegmentForwardWC.y, otherSegmentForwardWC.x);
  126. vec2 leftSumWC = thisSegmentLeftWC + otherSegmentLeftWC;
  127. float leftSumLength = length(leftSumWC);
  128. leftWC = leftSumLength < czm_epsilon6 ? thisSegmentLeftWC : (leftSumWC / leftSumLength);
  129. // The sine of the angle between the two vectors is given by the formula
  130. // |a x b| = |a||b|sin(theta)
  131. // which is
  132. // float sinAngle = length(cross(vec3(leftWC, 0.0), vec3(-thisSegmentForwardWC, 0.0)));
  133. // Because the z components of both vectors are zero, the x and y coordinate will be zero.
  134. // Therefore, the sine of the angle is just the z component of the cross product.
  135. vec2 u = -thisSegmentForwardWC;
  136. vec2 v = leftWC;
  137. float sinAngle = abs(u.x * v.y - u.y * v.x);
  138. expandWidth = clamp(expandWidth / sinAngle, 0.0, width * 2.0);
  139. }
  140. vec2 offset = leftWC * expandDirection * expandWidth * czm_pixelRatio;
  141. return vec4(clippedPositionWC.xy + offset, -clippedPositionWC.z, 1.0) * (czm_projection * clippedPositionEC).w;
  142. }
  143. vec4 getPolylineWindowCoordinates(vec4 position, vec4 previous, vec4 next, float expandDirection, float width, bool usePrevious, out float angle)
  144. {
  145. vec4 positionEC = czm_modelViewRelativeToEye * position;
  146. vec4 prevEC = czm_modelViewRelativeToEye * previous;
  147. vec4 nextEC = czm_modelViewRelativeToEye * next;
  148. return getPolylineWindowCoordinatesEC(positionEC, prevEC, nextEC, expandDirection, width, usePrevious, angle);
  149. }