- struct VsIn
- {
- float3 Position0 : Position0;
- float3 Position1 : Position1;
- };
- struct PsIn
- {
- float4 Position : SV_Position;
- // The parameters are constant across the line so use the nointerpolation attribute.
- // This is not necessarily required, but using this we can make the vertex shader slightly shorter.
- nointerpolation float4 KMF : KMF;
- };
- [Vertex shader]
- float4x4 ViewProj;
- float4 ScaleBias;
- PsIn main(VsIn In)
- {
- PsIn Out;
- float4 pos0 = mul(ViewProj, float4(In.Position0, 1.0));
- float4 pos1 = mul(ViewProj, float4(In.Position1, 1.0));
- Out.Position = pos0;
- // Compute screen-space position and direction of line
- float2 pos = (pos0.xy / pos0.w) * ScaleBias.xy + ScaleBias.zw;
- float2 dir = (pos1.xy / pos1.w) * ScaleBias.xy + ScaleBias.zw - pos;
- // Select between mostly horizontal or vertical
- bool x_gt_y = (abs(dir.x) > abs(dir.y));
- // Pass down the screen-space line equation
- if (x_gt_y)
- {
- float k = dir.y / dir.x;
- Out.KMF.xy = float2(k, -1);
- }
- else
- {
- float k = dir.x / dir.y;
- Out.KMF.xy = float2(-1, k);
- }
- Out.KMF.z = -dot(pos.xy, Out.KMF.xy);
- Out.KMF.w = asfloat(x_gt_y);
- return Out;
- }
- [Fragment shader]
- Texture2D BackBuffer;
- SamplerState Filter;
- float2 PixelSize;
- float4 main(PsIn In) : SV_Target
- {
- // Compute the difference between geometric line and sample position
- float diff = dot(In.KMF.xy, In.Position.xy) + In.KMF.z;
- // Compute the coverage of the neighboring surface
- float coverage = 0.5f - abs(diff);
- float2 offset = 0;
- if (coverage > 0)
- {
- // Select direction to sample a neighbor pixel
- float off = (diff >= 0)? 1 : -1;
- if (asuint(In.KMF.w))
- offset.y = off;
- else
- offset.x = off;
- }
- // Blend pixel with neighbor pixel using texture filtering and shifting the coordinate appropriately.
- return BackBuffer.Sample(Filter, (In.Position.xy + coverage * offset.xy) * PixelSize);
- }