PostprocessEffect.Fx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. //-----------------------------------------------------------------------------
  2. // PostprocessEffect.fx
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. // Settings controlling the edge detection filter.
  8. float EdgeWidth = 1;
  9. float EdgeIntensity = 1;
  10. // How sensitive should the edge detection be to tiny variations in the input data?
  11. // Smaller settings will make it pick up more subtle edges, while larger values get
  12. // rid of unwanted noise.
  13. float NormalThreshold = 0.5;
  14. float DepthThreshold = 0.1;
  15. // How dark should the edges get in response to changes in the input data?
  16. float NormalSensitivity = 1;
  17. float DepthSensitivity = 10;
  18. // How should the sketch effect respond to changes of brightness in the input scene?
  19. float SketchThreshold = 0.1;
  20. float SketchBrightness = 0.333;
  21. // Randomly offsets the sketch overlay pattern to create a hand-drawn animation effect.
  22. float2 SketchJitter;
  23. // Pass in the current screen resolution.
  24. float2 ScreenResolution;
  25. // This texture contains the main scene image, which the edge detection
  26. // and/or sketch filter are being applied over the top of.
  27. texture SceneTexture;
  28. sampler SceneSampler : register(s0) = sampler_state
  29. {
  30. Texture = (SceneTexture);
  31. MinFilter = Linear;
  32. MagFilter = Linear;
  33. AddressU = Clamp;
  34. AddressV = Clamp;
  35. };
  36. // This texture contains normals (in the color channels) and depth (in alpha)
  37. // for the main scene image. Differences in the normal and depth data are used
  38. // to detect where the edges of the model are.
  39. texture NormalDepthTexture;
  40. sampler NormalDepthSampler : register(s1) = sampler_state
  41. {
  42. Texture = (NormalDepthTexture);
  43. MinFilter = Linear;
  44. MagFilter = Linear;
  45. AddressU = Clamp;
  46. AddressV = Clamp;
  47. };
  48. // This texture contains an overlay sketch pattern, used to create the hatched
  49. // pencil drawing effect.
  50. texture SketchTexture;
  51. sampler SketchSampler : register(s2) = sampler_state
  52. {
  53. Texture = (SketchTexture);
  54. AddressU = Wrap;
  55. AddressV = Wrap;
  56. };
  57. // Pixel shader applies the edge detection and/or sketch filter postprocessing.
  58. // It is compiled several times using different settings for the uniform boolean
  59. // parameters, producing different optimized versions of the shader depending on
  60. // which combination of processing effects is desired.
  61. float4 PixelShaderFunction(float2 texCoord : TEXCOORD0, uniform bool applyEdgeDetect,
  62. uniform bool applySketch,
  63. uniform bool sketchInColor) : COLOR0
  64. {
  65. // Look up the original color from the main scene.
  66. float3 scene = tex2D(SceneSampler, texCoord);
  67. // Apply the sketch effect?
  68. if (applySketch)
  69. {
  70. // Adjust the scene color to remove very dark values and increase the contrast.
  71. float3 saturatedScene = saturate((scene - SketchThreshold) * 2);
  72. // Look up into the sketch pattern overlay texture.
  73. float3 sketchPattern = tex2D(SketchSampler, texCoord + SketchJitter);
  74. // Convert into negative color space, and combine the scene color with the
  75. // sketch pattern. We need to do this multiply in negative space to get good
  76. // looking results, because pencil sketching works by drawing black ink
  77. // over an initially white page, rather than adding light to an initially
  78. // black background as would be more common in computer graphics.
  79. float3 negativeSketch = (1 - saturatedScene) * (1 - sketchPattern);
  80. // Convert the result into a positive color space greyscale value.
  81. float sketchResult = dot(1 - negativeSketch, SketchBrightness);
  82. // Apply the sketch result to the main scene color.
  83. if (sketchInColor)
  84. scene *= sketchResult;
  85. else
  86. scene = sketchResult;
  87. }
  88. // Apply the edge detection filter?
  89. if (applyEdgeDetect)
  90. {
  91. // Look up four values from the normal/depth texture, offset along the
  92. // four diagonals from the pixel we are currently shading.
  93. float2 edgeOffset = EdgeWidth / ScreenResolution;
  94. float4 n1 = tex2D(NormalDepthSampler, texCoord + float2(-1, -1) * edgeOffset);
  95. float4 n2 = tex2D(NormalDepthSampler, texCoord + float2( 1, 1) * edgeOffset);
  96. float4 n3 = tex2D(NormalDepthSampler, texCoord + float2(-1, 1) * edgeOffset);
  97. float4 n4 = tex2D(NormalDepthSampler, texCoord + float2( 1, -1) * edgeOffset);
  98. // Work out how much the normal and depth values are changing.
  99. float4 diagonalDelta = abs(n1 - n2) + abs(n3 - n4);
  100. float normalDelta = dot(diagonalDelta.xyz, 1);
  101. float depthDelta = diagonalDelta.w;
  102. // Filter out very small changes, in order to produce nice clean results.
  103. normalDelta = saturate((normalDelta - NormalThreshold) * NormalSensitivity);
  104. depthDelta = saturate((depthDelta - DepthThreshold) * DepthSensitivity);
  105. // Does this pixel lie on an edge?
  106. float edgeAmount = saturate(normalDelta + depthDelta) * EdgeIntensity;
  107. // Apply the edge detection result to the main scene color.
  108. scene *= (1 - edgeAmount);
  109. }
  110. return float4(scene, 1);
  111. }
  112. // Compile the pixel shader for doing edge detection without any sketch effect.
  113. technique EdgeDetect
  114. {
  115. pass P0
  116. {
  117. PixelShader = compile ps_2_0 PixelShaderFunction(true, false, false);
  118. }
  119. }
  120. // Compile the pixel shader for doing edge detection with a monochrome sketch effect.
  121. technique EdgeDetectMonoSketch
  122. {
  123. pass P0
  124. {
  125. PixelShader = compile ps_2_0 PixelShaderFunction(true, true, false);
  126. }
  127. }
  128. // Compile the pixel shader for doing edge detection with a colored sketch effect.
  129. technique EdgeDetectColorSketch
  130. {
  131. pass P0
  132. {
  133. PixelShader = compile ps_2_0 PixelShaderFunction(true, true, true);
  134. }
  135. }
  136. // Compile the pixel shader for doing a monochrome sketch effect without edge detection.
  137. technique MonoSketch
  138. {
  139. pass P0
  140. {
  141. PixelShader = compile ps_2_0 PixelShaderFunction(false, true, false);
  142. }
  143. }
  144. // Compile the pixel shader for doing a colored sketch effect without edge detection.
  145. technique ColorSketch
  146. {
  147. pass P0
  148. {
  149. PixelShader = compile ps_2_0 PixelShaderFunction(false, true, true);
  150. }
  151. }