diff --git a/spine-xna/example-content/SpineEffectOutline.fx b/spine-xna/example-content/SpineEffectOutline.fx new file mode 100644 index 000000000..e83444264 --- /dev/null +++ b/spine-xna/example-content/SpineEffectOutline.fx @@ -0,0 +1,113 @@ +float4x4 World; +float4x4 View; +float4x4 Projection; + +sampler TextureSampler : register(s0); + +float _OutlineWidth = 3; +float4 _OutlineColor = float4(1, 1, 0, 1); +float _ThresholdEnd = 0.25; +float _OutlineSmoothness = 1.0; +float _OutlineMipLevel = 0; + +// TODO: add effect parameters here. + +struct VertexShaderInput +{ + float4 Position : POSITION0; + float4 Color : COLOR0; + float4 TextureCoordinate : TEXCOORD0; + float4 Color2 : COLOR1; +}; + +struct VertexShaderOutput +{ + float4 Position : POSITION0; + float4 Color : COLOR0; + float4 TextureCoordinate : TEXCOORD0; + float4 Color2 : COLOR1; +}; + +VertexShaderOutput VertexShaderFunction(VertexShaderInput input) +{ + VertexShaderOutput output; + + float4 worldPosition = mul(input.Position, World); + float4 viewPosition = mul(worldPosition, View); + output.Position = mul(viewPosition, Projection); + output.TextureCoordinate = input.TextureCoordinate; + output.Color = input.Color; + output.Color2 = input.Color2; + + return output; +} + +float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 +{ + float4 texColor = tex2D(TextureSampler, input.TextureCoordinate); + float alpha = texColor.a * input.Color.a; + float4 output; + output.a = alpha; + output.rgb = ((texColor.a - 1.0) * input.Color2.a + 1.0 - texColor.rgb) * input.Color2.rgb + texColor.rgb * input.Color.rgb; + + return output; +} + +// Outline pass +#define _USE8NEIGHBOURHOOD_ON + +float4 PixelShaderFunctionOutline(VertexShaderOutput i) : COLOR0 +{ + float4 texColor = float4(0,0,0,0); + + float uvDeltaPerPixel = max(ddx(i.TextureCoordinate), ddy(i.TextureCoordinate)); + float outlineWidthCompensated = _OutlineWidth * uvDeltaPerPixel; + float xOffset = outlineWidthCompensated; + float yOffset = outlineWidthCompensated; + float xOffsetDiagonal = outlineWidthCompensated * 0.7; + float yOffsetDiagonal = outlineWidthCompensated * 0.7; + + float pixelCenter = tex2D(TextureSampler, i.TextureCoordinate).a; + + float4 uvCenterWithLod = float4(i.TextureCoordinate.xy, 0, _OutlineMipLevel); + float pixelTop = tex2Dlod(TextureSampler, uvCenterWithLod + float4(0, yOffset, 0, 0)).a; + float pixelBottom = tex2Dlod(TextureSampler, uvCenterWithLod + float4(0, -yOffset, 0, 0)).a; + float pixelLeft = tex2Dlod(TextureSampler, uvCenterWithLod + float4(-xOffset, 0, 0, 0)).a; + float pixelRight = tex2Dlod(TextureSampler, uvCenterWithLod + float4(xOffset, 0, 0, 0)).a; +#ifdef _USE8NEIGHBOURHOOD_ON + float numSamples = 8; + float pixelTopLeft = tex2Dlod(TextureSampler, uvCenterWithLod + float4(-xOffsetDiagonal, yOffsetDiagonal, 0, 0)).a; + float pixelTopRight = tex2Dlod(TextureSampler, uvCenterWithLod + float4(xOffsetDiagonal, yOffsetDiagonal, 0, 0)).a; + float pixelBottomLeft = tex2Dlod(TextureSampler, uvCenterWithLod + float4(-xOffsetDiagonal, -yOffsetDiagonal, 0, 0)).a; + float pixelBottomRight = tex2Dlod(TextureSampler, uvCenterWithLod + float4(xOffsetDiagonal, -yOffsetDiagonal, 0, 0)).a; + float average = (pixelTop + pixelBottom + pixelLeft + pixelRight + + pixelTopLeft + pixelTopRight + pixelBottomLeft + pixelBottomRight) + * i.Color.a / numSamples; +#else // 4 neighbourhood + float numSamples = 1; + float average = (pixelTop + pixelBottom + pixelLeft + pixelRight) * i.Color.a / numSamples; +#endif + + float thresholdStart = _ThresholdEnd * (1.0 - _OutlineSmoothness); + float outlineAlpha = saturate((average - thresholdStart) / (_ThresholdEnd - thresholdStart)) - pixelCenter; + texColor.rgba = lerp(texColor, _OutlineColor, outlineAlpha); + return texColor; +} + +technique Technique1 +{ + pass OutlinePass + { + // TODO: set renderstates here. + + VertexShader = compile vs_3_0 VertexShaderFunction(); + PixelShader = compile ps_3_0 PixelShaderFunctionOutline(); + } + pass Pass2 + { + // TODO: set renderstates here. + + VertexShader = compile vs_2_0 VertexShaderFunction(); + PixelShader = compile ps_2_0 PixelShaderFunction(); + } +}