Advertisement
Guest User

The Witcher 3 - feedingGBuffer pixel shader (with spec tex)

a guest
Dec 28th, 2018
614
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.50 KB | None | 0 0
  1. cbuffer cbPerFrame : register (b0)
  2. {
  3. float4 cb0_v0;
  4. float4 cb0_v1;
  5. float4 cb0_v2;
  6. float4 cb0_v3;
  7. }
  8.  
  9. cbuffer cbData : register (b12)
  10. {
  11. float elapsedTime;
  12. uint numFrames;
  13. float2 pad;
  14.  
  15. float2 viewportSize;
  16. float2 viewportInvSize;
  17. }
  18.  
  19. cbuffer cbMaterial : register (b4)
  20. {
  21. float4 cb4_v0;
  22. float4 cb4_v1;
  23. float4 cb4_v2;
  24. float4 cb4_v3;
  25. float4 cb4_v4;
  26. }
  27.  
  28. Texture2D texture0 : register (t0);
  29. Texture2D texture1 : register (t1);
  30. Texture2D texture2 : register (t2);
  31. Texture2D texture13 : register (t13);
  32.  
  33. SamplerState samplerAnisoWrap : register (s0);
  34. SamplerState samplerPointClamp : register (s13);
  35.  
  36.  
  37. struct VS_OUTPUT
  38. {
  39. float4 out0 : PARAMS;
  40. float4 out1 : PARAMS1;
  41. float3 NormalW : NORMAL;
  42. float3 TangentW : TANGENT;
  43. };
  44.  
  45. struct PS_OUTPUT
  46. {
  47. float4 RT0 : SV_Target0;
  48. float4 RT1 : SV_Target1;
  49. float4 RT2 : SV_Target2;
  50. };
  51.  
  52. // Crytek's BFN
  53. // see:
  54. // https://github.com/CRYTEK/CRYENGINE/blob/release/Engine/Shaders/HWScripts/CryFX/Common.cfi#L383
  55. void CompressUnsignedNormalToNormalsBuffer( in Texture2D texNormalsFit, inout float3 vNormal )
  56. {
  57. // expand from unsigned
  58. //vNormal.rgb = vNormal.rgb * 2.h - 1.h;
  59.  
  60. // renormalize (needed if any blending or interpolation happened before)
  61. vNormal.rgb = normalize(vNormal.rgb);
  62.  
  63. // get unsigned normal for cubemap lookup (note the full float presision is required)
  64. float3 vNormalUns = abs( vNormal.rgb );
  65.  
  66. // get the main axis for cubemap lookup
  67. float maxNAbs = max(vNormalUns.z, max(vNormalUns.x, vNormalUns.y));
  68.  
  69. // get texture coordinates in a collapsed cubemap
  70. float2 vTexCoord = vNormalUns.z < maxNAbs ? (vNormalUns.y < maxNAbs?vNormalUns.yz : vNormalUns.xz) : vNormalUns.xy;
  71. vTexCoord = vTexCoord.x < vTexCoord.y ? (vTexCoord.yx) : (vTexCoord.xy);
  72. vTexCoord.y /= vTexCoord.x;
  73.  
  74. // fit normal into the edge of unit cube
  75. vNormal /= maxNAbs;
  76.  
  77. // look-up fitting length and scale the normal to get the best fit
  78. float fFittingScale = texNormalsFit.SampleLevel( samplerPointClamp, vTexCoord, 0 ).r;
  79.  
  80. // scale the normal to get the best fit
  81. vNormal *= fFittingScale;
  82. }
  83.  
  84. float getMaxComponent(in float3 color)
  85. {
  86. float result = max( color.x, max( color.y, color.z ) );
  87.  
  88. return result;
  89. }
  90.  
  91. float3 albedoColorFilter( in float3 color, in float desaturationFactor, in float3 desaturationValue )
  92. {
  93. float sumColorComponents = color.r + color.g + color.b;
  94.  
  95. float averageColorComponentValue = 0.3333 * sumColorComponents;
  96. float oneMinusAverageColorComponentValue = 1.0 - averageColorComponentValue;
  97.  
  98. float factor = 0.5 * (desaturationFactor - 1.0);
  99.  
  100. float avgColorComponent = lerp(averageColorComponentValue, oneMinusAverageColorComponentValue, saturate(factor));
  101. float3 desaturatedColor = saturate(color * desaturationValue * 1.5);
  102.  
  103. float mask = saturate( avgColorComponent * abs(factor) );
  104.  
  105. float3 finalColor = lerp( color, desaturatedColor, mask );
  106. return finalColor;
  107. }
  108.  
  109. PS_OUTPUT GBufferPS( in VS_OUTPUT Input, in uint bIsFrontFace : SV_IsFrontFace ) : SV_Target0
  110. {
  111. // We have three render target outputs
  112. PS_OUTPUT pout = (PS_OUTPUT) 0;
  113.  
  114. // Texcoords
  115. float2 Texcoords = Input.out1.xy;
  116.  
  117. // Data from textures
  118. float4 normalTex = texture1.Sample( samplerAnisoWrap, Texcoords );
  119. float3 colorTex = texture0.Sample( samplerAnisoWrap, Texcoords ).rgb;
  120.  
  121.  
  122. /* ALBEDO */
  123. // optional desaturation (?) filter
  124. float3 albedoColor = albedoColorFilter( colorTex, cb4_v1.x, cb4_v0.rgb );
  125. float albedoMaxComponent = getMaxComponent( albedoColor );
  126.  
  127. // I really have no idea what this is
  128. // In most of cases Vertex Shader outputs "paramZ" as 0
  129. float paramZ = Input.out0.z; // note, mostly 0
  130.  
  131. // Note that 0.70 are 0.85 are not present in the output assembly
  132. // Because I wanted to use lerp here I had to adjust them manually.
  133. float param = (albedoMaxComponent > 0.22) ? 0.70 : 0.85;
  134. float mulParam = lerp(1, param, paramZ);
  135.  
  136. // Output
  137. pout.RT0.rgb = albedoColor * mulParam;
  138. pout.RT0.a = cb4_v2.x;
  139.  
  140. /* NORMALS */
  141. float3 sampledNormal = ((normalTex.xyz - 0.5) * 2);
  142.  
  143. // Data to construct TBN matrix
  144. float3 Tangent = Input.TangentW.xyz;
  145. float3 Normal = Input.NormalW.xyz;
  146. float3 Bitangent;
  147. Bitangent.x = Input.out0.w;
  148. Bitangent.yz = Input.out1.zw;
  149.  
  150. // remove this saturate in real scenario, this is a hack to make sure normal-tbn multiplication
  151. // will have 'mad' instructions in assembly
  152. Bitangent = saturate(Bitangent);
  153.  
  154. float3x3 TBN = float3x3(Tangent, Bitangent, Normal);
  155. float3 normal = mul( sampledNormal, TBN );
  156.  
  157. // Trick to set normal vector properly in wireframe mode (I guess)
  158. //
  159. // See: https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-semantics
  160. //
  161. // * SV_IsFrontFace
  162. // Specifies whether a triangle is front facing.
  163. // For lines and points, IsFrontFace has the value true.
  164. // The exception is lines drawn out of triangles (wireframe mode), which sets IsFrontFace
  165. // the same way as rasterizing the triangle in solid mode.
  166. // Can be written to by the geometry shader, and read by the pixel shader.
  167. [branch] if (bIsFrontFace <= 0)
  168. {
  169. float cosTheta = dot(Input.NormalW, normal);
  170. float3 invNormal = cosTheta * Input.NormalW;
  171. normal = normal - 2*invNormal;
  172. }
  173.  
  174. /* SPECULAR */
  175. float3 specularTex = texture2.Sample( samplerAnisoWrap, Texcoords ).rgb;
  176.  
  177. // Similar algorithm as in Albedo. Calculate max component, compare this with
  178. // some threshold and calculate "minimum" value if needed.
  179. // Because in the scene I analyzed paramZ was set to zero, value from texture will be
  180. // the final result.
  181. float specularMaxComponent = getMaxComponent( specularTex );
  182. float3 specB = (specularMaxComponent > 0.2) ? specularTex : float3(0.12, 0.12, 0.12);
  183. float3 finalSpec = lerp(specularTex, specB, paramZ);
  184. pout.RT2.xyz = finalSpec;
  185.  
  186. /* REFLECTIVITY */
  187. float reflectivity = normalTex.a;
  188. float reflectivity2 = (reflectivity < 0.33) ? (reflectivity * 0.95) : 0.33;
  189.  
  190. float finalReflectivity = lerp(reflectivity, reflectivity2, paramZ);
  191. pout.RT1.a = finalReflectivity;
  192.  
  193. /* BEST FIT NORMALS */
  194. CompressUnsignedNormalToNormalsBuffer(texture13, normal.xyz);
  195.  
  196. // normals from [-1; 1] to [0 - 1]
  197. pout.RT1.xyz = normal * 0.5 + 0.5;
  198.  
  199. return pout;
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement