struct VSInput { float4 position : POSITION; float2 coord : TEXCOORD0; float2 offset : TEXCOORD1; float2 coordOffset : TEXCOORD2; }; cbuffer ConstantBuffer : register(b0) { float4x4 mvp; float opacity; float2 pixelSize; }; struct PSInput { float4 position : SV_POSITION; float2 coord : TEXCOORD0; float vertexOpacity : TEXCOORD3; }; Texture2D tex : register(t0); SamplerState samp : register(s0); PSInput VS_SmoothTexture(VSInput input) { PSInput result; float4 pos = mul(mvp, input.position); float2 coord = input.coord; if (input.offset.x != 0.0) { // In HLSL matrix packing is column-major by default (which is good) but the math is row-major (unlike GLSL). float4 delta = float4(mvp._11, mvp._21, mvp._31, mvp._41) * input.offset.x; float2 dir = delta.xy * pos.w - pos.xy * delta.w; float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize); dir -= ndir * delta.w * pos.w; float numerator = dot(dir, ndir * pos.w * pos.w); float scale = 0.0; if (numerator < 0.0) scale = 1.0; else scale = min(1.0, numerator / dot(dir, dir)); pos += scale * delta; coord.x += scale * input.coordOffset.x; } if (input.offset.y != 0.0) { float4 delta = float4(mvp._12, mvp._22, mvp._32, mvp._42) * input.offset.y; float2 dir = delta.xy * pos.w - pos.xy * delta.w; float2 ndir = 0.5 * pixelSize * normalize(dir / pixelSize); dir -= ndir * delta.w * pos.w; float numerator = dot(dir, ndir * pos.w * pos.w); float scale = 0.0; if (numerator < 0.0) scale = 1.0; else scale = min(1.0, numerator / dot(dir, dir)); pos += scale * delta; coord.y += scale * input.coordOffset.y; } if ((input.offset.x != 0.0 || input.offset.y != 0.0) && (input.coordOffset.x == 0.0 && input.coordOffset.y == 0.0)) result.vertexOpacity = 0.0; else result.vertexOpacity = opacity; result.position = pos; result.coord = coord; return result; } float4 PS_SmoothTexture(PSInput input) : SV_TARGET { return tex.Sample(samp, input.coord) * input.vertexOpacity; }