Lux_Procedural_Texturing.hlsl 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // https://github.com/UnityLabs/procedural-stochastic-texturing/blob/master/Editor/ProceduralTexture2D/SampleProceduralTexture2DNode.cs
  2. // Unity 2019.1. needs a float version
  3. // https://www.shadertoy.com/view/4djSRW
  4. float2 hash22(float2 p) {
  5. float3 p3 = frac(float3(p.xyx) * float3(.1031, .1030, .0973));
  6. p3 += dot(p3, p3.yzx+33.33);
  7. return frac((p3.xx+p3.yz)*p3.zy);
  8. }
  9. void StochasticSample_half(
  10. SamplerState samplerTex, // We have to use trilinear/repeat on all textures
  11. SamplerState samplerLUT,
  12. // Base inputs
  13. half Blend,
  14. float2 uv,
  15. // Albedo
  16. Texture2D textureAlbedo,
  17. Texture2D LUT,
  18. float3 InputSize,
  19. half4 CompressionScalars_Albedo,
  20. // sRGB Color Inputs
  21. half3 ColorSpaceOrigin_Albedo,
  22. half3 ColorSpaceVector1_Albedo,
  23. half3 ColorSpaceVector2_Albedo,
  24. half3 ColorSpaceVector3_Albedo,
  25. // Normal
  26. Texture2D textureNormal,
  27. Texture2D LUTNormal,
  28. float3 InputSize_Normal,
  29. float4 CompressionScalars_Normal,
  30. // MaskMap – might be Specular/Smoothness or Metallic Smoothness
  31. Texture2D textureMask,
  32. Texture2D LUTMask,
  33. float3 InputSize_Mask,
  34. half4 CompressionScalars_Mask,
  35. bool MaskUsesSRGB,
  36. // sRGB Color Inputs
  37. half3 ColorSpaceOrigin_Mask,
  38. half3 ColorSpaceVector1_Mask,
  39. half3 ColorSpaceVector2_Mask,
  40. half3 ColorSpaceVector3_Mask,
  41. // Output
  42. out half3 FinalAlbedo,
  43. out half FinalAlpha,
  44. out half3 FinalNormal,
  45. out half4 FinalMask
  46. )
  47. {
  48. float2 uvScaled = uv * 3.464; // 2 * sqrt(3)
  49. const float2x2 gridToSkewedGrid = float2x2(1.0, 0.0, -0.57735027, 1.15470054);
  50. float2 skewedCoord = mul(gridToSkewedGrid, uvScaled);
  51. int2 baseId = int2(floor(skewedCoord));
  52. float3 temp = float3(frac(skewedCoord), 0);
  53. temp.z = 1.0 - temp.x - temp.y;
  54. half w1, w2, w3;
  55. int2 vertex1, vertex2, vertex3;
  56. if (temp.z > 0.0) {
  57. w1 = temp.z;
  58. w2 = temp.y;
  59. w3 = temp.x;
  60. vertex1 = baseId;
  61. vertex2 = baseId + int2(0, 1);
  62. vertex3 = baseId + int2(1, 0);
  63. }
  64. else {
  65. w1 = -temp.z;
  66. w2 = 1.0 - temp.y;
  67. w3 = 1.0 - temp.x;
  68. vertex1 = baseId + int2(1, 1);
  69. vertex2 = baseId + int2(1, 0);
  70. vertex3 = baseId + int2(0, 1);
  71. }
  72. const float2x2 hashMatrix = float2x2(127.1, 311.7, 269.5, 183.3);
  73. const float hashFactor = 3758.5453;
  74. float2 uv1 = uv + frac(sin(mul(hashMatrix, (float2)vertex1)) * hashFactor);
  75. float2 uv2 = uv + frac(sin(mul(hashMatrix, (float2)vertex2)) * hashFactor);
  76. float2 uv3 = uv + frac(sin(mul(hashMatrix, (float2)vertex3)) * hashFactor);
  77. // Use a hash function which does not include sin
  78. // Adds a little bit visible tiling...
  79. // float2 uv1 = uv + hash22( (float2)vertex1 );
  80. // float2 uv2 = uv + hash22( (float2)vertex2 );
  81. // float2 uv3 = uv + hash22( (float2)vertex3 );
  82. float2 duvdx = ddx(uv);
  83. float2 duvdy = ddy(uv);
  84. // Get weights
  85. half exponent = 1.0h + Blend * 15.0h;
  86. #pragma warning (disable : 3571)
  87. w1 = pow(w1, exponent);
  88. w2 = pow(w2, exponent);
  89. w3 = pow(w3, exponent);
  90. #pragma warning (enable : 3571)
  91. // As all pows use the same exponent we can help the compiler:
  92. // Why does this introduce artifacts?
  93. //exponent = log(exponent);
  94. //w1 = exp(w1 * exponent);
  95. //w2 = exp(w2 * exponent);
  96. //w3 = exp(w3 * exponent);
  97. // Lets help the compiler here:
  98. half sum = rcp(w1 + w2 + w3);
  99. w1 = w1 * sum;
  100. w2 = w2 * sum;
  101. w3 = w3 * sum;
  102. half wrsrqt = rsqrt(w1 * w1 + w2 * w2 + w3 * w3);
  103. // Albedo – Sample Gaussion values from transformed input
  104. half4 G1 = SAMPLE_TEXTURE2D_GRAD(textureAlbedo, samplerTex, uv1, duvdx, duvdy);
  105. half4 G2 = SAMPLE_TEXTURE2D_GRAD(textureAlbedo, samplerTex, uv2, duvdx, duvdy);
  106. half4 G3 = SAMPLE_TEXTURE2D_GRAD(textureAlbedo, samplerTex, uv3, duvdx, duvdy);
  107. half4 G = w1 * G1 + w2 * G2 + w3 * G3;
  108. G = G - 0.5h;
  109. G = G * wrsrqt; //rsqrt(w1 * w1 + w2 * w2 + w3 * w3);
  110. G = G * CompressionScalars_Albedo;
  111. G = G + 0.5h;
  112. // Normal – Sample Gaussion values from transformed input
  113. half4 N1 = SAMPLE_TEXTURE2D_GRAD(textureNormal, samplerTex, uv1, duvdx, duvdy);
  114. half4 N2 = SAMPLE_TEXTURE2D_GRAD(textureNormal, samplerTex, uv2, duvdx, duvdy);
  115. half4 N3 = SAMPLE_TEXTURE2D_GRAD(textureNormal, samplerTex, uv3, duvdx, duvdy);
  116. half4 N = w1 * N1 + w2 * N2 + w3 * N3;
  117. N = N - 0.5h;
  118. N = N * wrsrqt; //rsqrt(w1 * w1 + w2 * w2 + w3 * w3);
  119. N = N * CompressionScalars_Normal;
  120. N = N + 0.5h;
  121. // Mask – Sample Gaussion values from transformed input
  122. half4 M1 = SAMPLE_TEXTURE2D_GRAD(textureMask, samplerTex, uv1, duvdx, duvdy);
  123. half4 M2 = SAMPLE_TEXTURE2D_GRAD(textureMask, samplerTex, uv2, duvdx, duvdy);
  124. half4 M3 = SAMPLE_TEXTURE2D_GRAD(textureMask, samplerTex, uv3, duvdx, duvdy);
  125. half4 M = w1 * M1 + w2 * M2 + w3 * M3;
  126. M = M - 0.5h;
  127. M = M * wrsrqt; //rsqrt(w1 * w1 + w2 * w2 + w3 * w3);
  128. M = M * CompressionScalars_Normal;
  129. M = M + 0.5h;
  130. // TODO: Check if we need to use scalars if normal or mask have different sizes compared to albedo.
  131. // I think it looks totally fine without using scalars.
  132. duvdx *= InputSize.xy;
  133. duvdy *= InputSize.xy;
  134. float delta_max_sqr = max(dot(duvdx, duvdx), dot(duvdy, duvdy));
  135. float mml = 0.5 * log2(delta_max_sqr);
  136. float LOD = max(0, mml) * InputSize.z; // was: max(0, mml) / InputSize.z; // but we feed in: (1.0 / InputSize.z)
  137. // Albedo – Fetch LUT
  138. half4 color;
  139. color.r = SAMPLE_TEXTURE2D_LOD(LUT, samplerLUT, float2(G.r, LOD), 0).r;
  140. color.g = SAMPLE_TEXTURE2D_LOD(LUT, samplerLUT, float2(G.g, LOD), 0).g;
  141. color.b = SAMPLE_TEXTURE2D_LOD(LUT, samplerLUT, float2(G.b, LOD), 0).b;
  142. color.a = SAMPLE_TEXTURE2D_LOD(LUT, samplerLUT, float2(G.a, LOD), 0).a;
  143. // Needed by sRGB color textures
  144. FinalAlbedo = ColorSpaceOrigin_Albedo + ColorSpaceVector1_Albedo * color.r + ColorSpaceVector2_Albedo * color.g + ColorSpaceVector3_Albedo * color.b;
  145. FinalAlpha = color.a;
  146. // Normal – Fetch LUT
  147. half4 normal;
  148. normal.r = SAMPLE_TEXTURE2D_LOD(LUTNormal, samplerLUT, float2(N.r, LOD), 0).r;
  149. normal.g = SAMPLE_TEXTURE2D_LOD(LUTNormal, samplerLUT, float2(N.g, LOD), 0).g;
  150. normal.b = SAMPLE_TEXTURE2D_LOD(LUTNormal, samplerLUT, float2(N.b, LOD), 0).b;
  151. normal.a = SAMPLE_TEXTURE2D_LOD(LUTNormal, samplerLUT, float2(N.a, LOD), 0).a;
  152. // Normal is either BC5 or DXT5nm – what is about mobile?
  153. #if defined(UNITY_NO_DXT5nm)
  154. FinalNormal = UnpackNormalRGBNoScale(normal);
  155. #else
  156. FinalNormal = UnpackNormalmapRGorAG(normal);
  157. #endif
  158. // Mask – Fetch LUT
  159. half4 mask;
  160. mask.r = SAMPLE_TEXTURE2D_LOD(LUTMask, samplerLUT, float2(M.r, LOD), 0).r;
  161. mask.g = SAMPLE_TEXTURE2D_LOD(LUTMask, samplerLUT, float2(M.g, LOD), 0).g;
  162. mask.b = SAMPLE_TEXTURE2D_LOD(LUTMask, samplerLUT, float2(M.b, LOD), 0).b;
  163. mask.a = SAMPLE_TEXTURE2D_LOD(LUTMask, samplerLUT, float2(M.a, LOD), 0).a;
  164. // Handle sRGB
  165. if(MaskUsesSRGB) {
  166. FinalMask.rgb = ColorSpaceOrigin_Mask + ColorSpaceVector1_Mask * mask.r + ColorSpaceVector2_Mask * mask.g + ColorSpaceVector3_Mask * mask.b;
  167. FinalMask.a = mask.a;
  168. }
  169. else {
  170. FinalMask = mask;
  171. }
  172. }
  173. void StochasticSample_float(
  174. SamplerState samplerTex, // We have to use trilinear/repeat on all textures
  175. SamplerState samplerLUT,
  176. // Base inputs
  177. half Blend,
  178. float2 uv,
  179. // Albedo
  180. Texture2D textureAlbedo,
  181. Texture2D LUT,
  182. float3 InputSize,
  183. half4 CompressionScalars_Albedo,
  184. // sRGB Color Inputs
  185. half3 ColorSpaceOrigin_Albedo,
  186. half3 ColorSpaceVector1_Albedo,
  187. half3 ColorSpaceVector2_Albedo,
  188. half3 ColorSpaceVector3_Albedo,
  189. // Normal
  190. Texture2D textureNormal,
  191. Texture2D LUTNormal,
  192. float3 InputSize_Normal,
  193. float4 CompressionScalars_Normal,
  194. // MaskMap – might be Specular/Smoothness or Metallic Smoothness
  195. Texture2D textureMask,
  196. Texture2D LUTMask,
  197. float3 InputSize_Mask,
  198. half4 CompressionScalars_Mask,
  199. bool MaskUsesSRGB,
  200. // sRGB Color Inputs
  201. half3 ColorSpaceOrigin_Mask,
  202. half3 ColorSpaceVector1_Mask,
  203. half3 ColorSpaceVector2_Mask,
  204. half3 ColorSpaceVector3_Mask,
  205. // Output
  206. out half3 FinalAlbedo,
  207. out half FinalAlpha,
  208. out half3 FinalNormal,
  209. out half4 FinalMask
  210. )
  211. {
  212. StochasticSample_half (
  213. samplerTex, samplerLUT, Blend, uv,
  214. textureAlbedo, LUT, InputSize, CompressionScalars_Albedo, ColorSpaceOrigin_Albedo, ColorSpaceVector1_Albedo, ColorSpaceVector2_Albedo, ColorSpaceVector3_Albedo,
  215. textureNormal, LUTNormal, InputSize_Normal, CompressionScalars_Normal,
  216. textureMask, LUTMask, InputSize_Mask, CompressionScalars_Mask, MaskUsesSRGB, ColorSpaceOrigin_Mask, ColorSpaceVector1_Mask, ColorSpaceVector2_Mask, ColorSpaceVector3_Mask,
  217. FinalAlbedo, FinalAlpha, FinalNormal, FinalMask
  218. );
  219. }