123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- #ifndef MESH_CHAIN
- #define MESH_CHAIN
- // UNITY_SHADER_NO_UPGRADE
- half4 _Color; // What color to tint the line
- half4 _lineSettings; // Settings for how to shade the line - basically applying a levels filter to the gradient
- half3 _lineRadius; // x: Element size multiplier, y: min, z: max
- struct appdata_meshChain
- {
- float4 vertex : POSITION;
- float4 texcoord : TEXCOORD0;
- float4 texcoord1 : TEXCOORD1;
- fixed4 color : COLOR;
- };
- struct meshChain_vertex
- {
- float4 pos : SV_POSITION;
- float4 uv : TEXCOORD0;
- fixed4 color : COLOR;
- };
- meshChain_vertex vert(appdata_meshChain v)
- {
- meshChain_vertex o;
- // In 5.4 and later we have stereo instance rendering so we go through the
- // ClipPos function which is aware of the proper projection matrix per-eye
- #if LINE_WORLD_SPACE
- o.pos = mul(UNITY_MATRIX_VP, v.vertex);
- #elif UNITY_VERSION < 540
- o.pos = UnityObjectToClipPos(v.vertex);
- #else
- o.pos = UnityObjectToClipPos(v.vertex);
- #endif
- // We calculate the aspect ratio since the lines are
- // being transformed into a psuedo-screen space area
- half aspectRatio = _ScreenParams.x / _ScreenParams.y;
-
- // Determine the location of our neighbor
- #if LINE_WORLD_SPACE
- half4 neighborPos = mul(UNITY_MATRIX_VP, v.texcoord1);
- #elif UNITY_VERSION < 540
- half4 neighborPos = UnityObjectToClipPos(v.texcoord1);
- #else
- half4 neighborPos = UnityObjectToClipPos(v.texcoord1);
- #endif
- // We calculate the distance this billboard or pipe expands at each end
- // We use this for the vertex deformation and proper non-perspective texture mapping
- #if LINE_FIXED_WIDTH
- half expandDistanceSource = clamp(_lineRadius.x * o.pos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.z;
- half expandDistanceDest = clamp(_lineRadius.x * neighborPos.w * .1, _lineRadius.y, _lineRadius.z) * v.texcoord.w;
- #else
- half expandDistanceSource = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.z;
- half expandDistanceDest = max(_lineRadius * .1, _lineRadius.y) * v.texcoord.w;
- #endif
- // If the screen space distance between these two points is under a threshold, we are a billboard
- // Otherwise, we are a pipe
- half2 perpVec = (neighborPos.xy / neighborPos.w) - (o.pos.xy / o.pos.w);
- half pipeFlag = step(.001, length(perpVec));
- perpVec = normalize(perpVec).yx;
- perpVec.y *= -1;
- perpVec.xy *= (2 * (v.texcoord.x - .5)) * (2 * (v.texcoord.y - .5));
- // Billboard logic
- // We billboard based off the UV's we had stored
- // Since the UV's represent each corner, we convert these into offsets
- half2 billboardVec = 2 * (v.texcoord.xy - .5);
- // Whether this element is a billboard or a pipe is encoded in the secondary texture coordinates
- // A 0 on the u coordinate specifies using the billboard rendering mode
- // A 1 on the u coordinate specifies using the pipe rendering mode
- o.pos.x += lerp(billboardVec.x, perpVec.x, pipeFlag) * expandDistanceSource;
- o.pos.y += lerp(billboardVec.y, perpVec.y, pipeFlag) * expandDistanceSource*aspectRatio;
- // We store the w coordinate of the worldspace position separately here
- // We need to conditionally undo the perspective correction on these UV coordinates
- // And the w coordinate is needed for that
- float sizeRatio = ((expandDistanceSource + expandDistanceDest) / expandDistanceDest);
- o.uv = float4(v.texcoord.x, v.texcoord.y, pipeFlag, sizeRatio);
- o.uv.y = o.uv.y * (1.0 - pipeFlag) + .5 * pipeFlag;
- o.uv.xy *= sizeRatio;
- o.color = v.color * _Color;
- return o;
- }
-
- //----------------------------------------------
- // Function that takes an input brightness,
- // and applies the levels logic we've described
- //----------------------------------------------
- // curve.x : min range (0 - 1, based on brightness)
- // curve.y : max range (1 - 0, based on brightness)
- // curve.z : bend (.5 is linear)
- fixed applyLevels(fixed original, fixed3 curve)
- {
- // Any value less than 1/256 (the minimum the color variable can represent in the editor)
- // is clamped to 0 to prevent texture bleeding
- fixed inRange = saturate((original - curve.x) / (curve.y - curve.x)) * step(1.0 / 256.0, original);
- // We take this in-range value and apply a power function to it
- // We calculate the power from our bend value with the following logic
- // Any curve value from 0 to .5 goes from 1/32 to 1
- // Any curve value from .5 to 1 goes from 1 to 32
- // This lets us have really strong curve controls
- // Pow is not necessarily cheap, but equivalent perf to lerping
- // between a curve that bows out and one that bows in
- half bendValue = curve.z;
- fixed powValue = (saturate(-(bendValue - .5)) * 5) + (1 / (saturate(bendValue - .5) * 5 + 1));
- return pow(inRange, powValue);
- }
- half4 frag(meshChain_vertex i) : COLOR
- {
- // This used to be a texture lookup, we have now turned it into pure math
- // Undo the perspective correction
- float2 texCoord = i.uv.xy / i.uv.w;
- // Calculate the how close to the center of the billboard or pipe we are, and convert
- // that to a brightness value
- half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
- // Apply our curve logic and color tint
- return applyLevels(lineAlpha*i.color.a, _lineSettings.rgb) * i.color;
- }
- half4 fragInvert(meshChain_vertex i) : COLOR
- {
- // This used to be a texture lookup, we have now turned it into pure math
- // Undo the perspective correction
- float2 texCoord = i.uv.xy / i.uv.w;
- // Calculate the how close to the center of the billboard or pipe we are, and convert
- // that to a brightness value
- half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
- // Apply our curve logic and color tint
- return lerp(i.color, half4(1,1,1,1), 1 - applyLevels(lineAlpha * i.color.a, _lineSettings.rgb));
- }
- half4 fragAlphaMask(meshChain_vertex i) : COLOR
- {
- // This used to be a texture lookup, we have now turned it into pure math
- // Undo the perspective correction
- float2 texCoord = i.uv.xy / i.uv.w;
- // Calculate the how close to the center of the billboard or pipe we are, and convert
- // that to a brightness value
- half lineAlpha = 1 - saturate(length(texCoord * 2 - float2(1.0, 1.0)));
- lineAlpha = lerp(1, 1 - applyLevels(lineAlpha, _lineSettings.rgb), i.color.a);
- return half4(0, 0, 0, lineAlpha);
- }
- half4 fragColor(meshChain_vertex i) : COLOR
- {
- return half4(i.color.rgb,1);
- }
- #endif // MESH_CHAIN
|