MeshChain.cginc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #ifndef MESH_CHAIN
  2. #define MESH_CHAIN
  3. // UNITY_SHADER_NO_UPGRADE
  4. half4 _Color; // What color to tint the line
  5. half4 _lineSettings; // Settings for how to shade the line - basically applying a levels filter to the gradient
  6. half3 _lineRadius; // x: Element size multiplier, y: min, z: max
  7. struct appdata_meshChain
  8. {
  9. float4 vertex : POSITION;
  10. float4 texcoord : TEXCOORD0;
  11. float4 texcoord1 : TEXCOORD1;
  12. fixed4 color : COLOR;
  13. };
  14. struct meshChain_vertex
  15. {
  16. float4 pos : SV_POSITION;
  17. float4 uv : TEXCOORD0;
  18. fixed4 color : COLOR;
  19. };
  20. meshChain_vertex vert(appdata_meshChain v)
  21. {
  22. meshChain_vertex o;
  23. // In 5.4 and later we have stereo instance rendering so we go through the
  24. // ClipPos function which is aware of the proper projection matrix per-eye
  25. #if LINE_WORLD_SPACE
  26. o.pos = mul(UNITY_MATRIX_VP, v.vertex);
  27. #elif UNITY_VERSION < 540
  28. o.pos = UnityObjectToClipPos(v.vertex);
  29. #else
  30. o.pos = UnityObjectToClipPos(v.vertex);
  31. #endif
  32. // We calculate the aspect ratio since the lines are
  33. // being transformed into a psuedo-screen space area
  34. half aspectRatio = _ScreenParams.x / _ScreenParams.y;
  35. // Determine the location of our neighbor
  36. #if LINE_WORLD_SPACE
  37. half4 neighborPos = mul(UNITY_MATRIX_VP, v.texcoord1);
  38. #elif UNITY_VERSION < 540
  39. half4 neighborPos = UnityObjectToClipPos(v.texcoord1);
  40. #else
  41. half4 neighborPos = UnityObjectToClipPos(v.texcoord1);
  42. #endif
  43. // We calculate the distance this billboard or pipe expands at each end
  44. // We use this for the vertex deformation and proper non-perspective texture mapping
  45. #if LINE_FIXED_WIDTH
  46. half expandDistanceSource = clamp(_lineRadius.x * o.pos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.z;
  47. half expandDistanceDest = clamp(_lineRadius.x * neighborPos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.w;
  48. #else
  49. half expandDistanceSource = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.z;
  50. half expandDistanceDest = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.w;
  51. #endif
  52. // If the screen space distance between these two points is under a threshold, we are a billboard
  53. // Otherwise, we are a pipe
  54. half2 perpVec = (neighborPos.xy / neighborPos.w) - (o.pos.xy / o.pos.w);
  55. half pipeFlag = step(.001, length(perpVec));
  56. perpVec = normalize(perpVec).yx;
  57. perpVec.y *= -1;
  58. perpVec.xy *= (2 * (v.texcoord.x - .5)) * (2 * (v.texcoord.y - .5));
  59. // Billboard logic
  60. // We billboard based off the UV's we had stored
  61. // Since the UV's represent each corner, we convert these into offsets
  62. half2 billboardVec = 2 * (v.texcoord.xy - .5);
  63. // Whether this element is a billboard or a pipe is encoded in the secondary texture coordinates
  64. // A 0 on the u coordinate specifies using the billboard rendering mode
  65. // A 1 on the u coordinate specifies using the pipe rendering mode
  66. o.pos.x += lerp(billboardVec.x, perpVec.x, pipeFlag) * expandDistanceSource;
  67. o.pos.y += lerp(billboardVec.y, perpVec.y, pipeFlag) * expandDistanceSource*aspectRatio;
  68. // We store the w coordinate of the worldspace position separately here
  69. // We need to conditionally undo the perspective correction on these UV coordinates
  70. // And the w coordinate is needed for that
  71. float sizeRatio = ((expandDistanceSource + expandDistanceDest) / expandDistanceDest);
  72. o.uv = float4(v.texcoord.x, v.texcoord.y, pipeFlag, sizeRatio);
  73. o.uv.y = o.uv.y * (1.0 - pipeFlag) + .5 * pipeFlag;
  74. o.uv.xy *= sizeRatio;
  75. o.color = v.color * _Color;
  76. return o;
  77. }
  78. //----------------------------------------------
  79. // Function that takes an input brightness,
  80. // and applies the levels logic we've described
  81. //----------------------------------------------
  82. // curve.x : min range (0 - 1, based on brightness)
  83. // curve.y : max range (1 - 0, based on brightness)
  84. // curve.z : bend (.5 is linear)
  85. fixed applyLevels(fixed original, fixed3 curve)
  86. {
  87. // Any value less than 1/256 (the minimum the color variable can represent in the editor)
  88. // is clamped to 0 to prevent texture bleeding
  89. fixed inRange = saturate((original - curve.x) / (curve.y - curve.x)) * step(1.0 / 256.0, original);
  90. // We take this in-range value and apply a power function to it
  91. // We calculate the power from our bend value with the following logic
  92. // Any curve value from 0 to .5 goes from 1/32 to 1
  93. // Any curve value from .5 to 1 goes from 1 to 32
  94. // This lets us have really strong curve controls
  95. // Pow is not necessarily cheap, but equivalent perf to lerping
  96. // between a curve that bows out and one that bows in
  97. half bendValue = curve.z;
  98. fixed powValue = (saturate(-(bendValue - .5)) * 5) + (1 / (saturate(bendValue - .5) * 5 + 1));
  99. return pow(inRange, powValue);
  100. }
  101. half4 frag(meshChain_vertex i) : COLOR
  102. {
  103. // This used to be a texture lookup, we have now turned it into pure math
  104. // Undo the perspective correction
  105. float2 texCoord = i.uv.xy / i.uv.w;
  106. // Calculate the how close to the center of the billboard or pipe we are, and convert
  107. // that to a brightness value
  108. half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
  109. // Apply our curve logic and color tint
  110. return applyLevels(lineAlpha*i.color.a, _lineSettings.rgb) * i.color;
  111. }
  112. half4 fragInvert(meshChain_vertex i) : COLOR
  113. {
  114. // This used to be a texture lookup, we have now turned it into pure math
  115. // Undo the perspective correction
  116. float2 texCoord = i.uv.xy / i.uv.w;
  117. // Calculate the how close to the center of the billboard or pipe we are, and convert
  118. // that to a brightness value
  119. half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
  120. // Apply our curve logic and color tint
  121. return lerp(i.color, half4(1,1,1,1), 1 - applyLevels(lineAlpha * i.color.a, _lineSettings.rgb));
  122. }
  123. half4 fragAlphaMask(meshChain_vertex i) : COLOR
  124. {
  125. // This used to be a texture lookup, we have now turned it into pure math
  126. // Undo the perspective correction
  127. float2 texCoord = i.uv.xy / i.uv.w;
  128. // Calculate the how close to the center of the billboard or pipe we are, and convert
  129. // that to a brightness value
  130. half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
  131. lineAlpha = lerp(1, 1 - applyLevels(lineAlpha, _lineSettings.rgb), i.color.a);
  132. return half4(0, 0, 0, lineAlpha);
  133. }
  134. half4 fragColor(meshChain_vertex i) : COLOR
  135. {
  136. return half4(i.color.rgb,1);
  137. }
  138. #endif // MESH_CHAIN