1. // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
  2.  
  3. #ifndef UNITY_STANDARD_UTILS_INCLUDED
  4. #define UNITY_STANDARD_UTILS_INCLUDED
  5.  
  6. #include "UnityCG.cginc"
  7. #include "UnityStandardConfig.cginc"
  8.  
  9. // Helper functions, maybe move into UnityCG.cginc
  10.  
  11. half SpecularStrength(half3 specular)
  12. {
  13. #if (SHADER_TARGET < 30)
  14. // SM2.0: instruction count limitation
  15. // SM2.0: simplified SpecularStrength
  16. return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
  17. #else
  18. return max (max (specular.r, specular.g), specular.b);
  19. #endif
  20. }
  21.  
  22. // Diffuse/Spec Energy conservation
  23. inline half3 EnergyConservationBetweenDiffuseAndSpecular (half3 albedo, half3 specColor, out half oneMinusReflectivity)
  24. {
  25. oneMinusReflectivity = 1 - SpecularStrength(specColor);
  26. #if !UNITY_CONSERVE_ENERGY
  27. return albedo;
  28. #elif UNITY_CONSERVE_ENERGY_MONOCHROME
  29. return albedo * oneMinusReflectivity;
  30. #else
  31. return albedo * (half3(1,1,1) - specColor);
  32. #endif
  33. }
  34.  
  35. inline half OneMinusReflectivityFromMetallic(half metallic)
  36. {
  37. // We'll need oneMinusReflectivity, so
  38. // 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
  39. // store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
  40. // 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
  41. // = alpha - metallic * alpha
  42. half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
  43. return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
  44. }
  45.  
  46. inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
  47. {
  48. specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
  49. oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
  50. return albedo * oneMinusReflectivity;
  51. }
  52.  
  53. inline half3 PreMultiplyAlpha (half3 diffColor, half alpha, half oneMinusReflectivity, out half outModifiedAlpha)
  54. {
  55. #if defined(_ALPHAPREMULTIPLY_ON)
  56. // NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
  57.  
  58. // Transparency 'removes' from Diffuse component
  59. diffColor *= alpha;
  60.  
  61. #if (SHADER_TARGET < 30)
  62. // SM2.0: instruction count limitation
  63. // Instead will sacrifice part of physically based transparency where amount Reflectivity is affecting Transparency
  64. // SM2.0: uses unmodified alpha
  65. outModifiedAlpha = alpha;
  66. #else
  67. // Reflectivity 'removes' from the rest of components, including Transparency
  68. // outAlpha = 1-(1-alpha)*(1-reflectivity) = 1-(oneMinusReflectivity - alpha*oneMinusReflectivity) =
  69. // = 1-oneMinusReflectivity + alpha*oneMinusReflectivity
  70. outModifiedAlpha = 1-oneMinusReflectivity + alpha*oneMinusReflectivity;
  71. #endif
  72. #else
  73. outModifiedAlpha = alpha;
  74. #endif
  75. return diffColor;
  76. }
  77.  
  78. // Same as ParallaxOffset in Unity CG, except:
  79. // *) precision - half instead of float
  80. half2 ParallaxOffset1Step (half h, half height, half3 viewDir)
  81. {
  82. h = h * height - height/2.0;
  83. half3 v = normalize(viewDir);
  84. v.z += 0.42;
  85. return h * (v.xy / v.z);
  86. }
  87.  
  88. half LerpOneTo(half b, half t)
  89. {
  90. half oneMinusT = 1 - t;
  91. return oneMinusT + b * t;
  92. }
  93.  
  94. half3 LerpWhiteTo(half3 b, half t)
  95. {
  96. half oneMinusT = 1 - t;
  97. return half3(oneMinusT, oneMinusT, oneMinusT) + b * t;
  98. }
  99.  
  100. half3 UnpackScaleNormalDXT5nm(half4 packednormal, half bumpScale)
  101. {
  102. half3 normal;
  103. normal.xy = (packednormal.wy * 2 - 1);
  104. #if (SHADER_TARGET >= 30)
  105. // SM2.0: instruction count limitation
  106. // SM2.0: normal scaler is not supported
  107. normal.xy *= bumpScale;
  108. #endif
  109. normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
  110. return normal;
  111. }
  112.  
  113. half3 UnpackScaleNormalRGorAG(half4 packednormal, half bumpScale)
  114. {
  115. #if defined(UNITY_NO_DXT5nm)
  116. half3 normal = packednormal.xyz * 2 - 1;
  117. #if (SHADER_TARGET >= 30)
  118. // SM2.0: instruction count limitation
  119. // SM2.0: normal scaler is not supported
  120. normal.xy *= bumpScale;
  121. #endif
  122. return normal;
  123. #else
  124. // This do the trick
  125. packednormal.x *= packednormal.w;
  126.  
  127. half3 normal;
  128. normal.xy = (packednormal.xy * 2 - 1);
  129. #if (SHADER_TARGET >= 30)
  130. // SM2.0: instruction count limitation
  131. // SM2.0: normal scaler is not supported
  132. normal.xy *= bumpScale;
  133. #endif
  134. normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
  135. return normal;
  136. #endif
  137. }
  138.  
  139. half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
  140. {
  141. return UnpackScaleNormalRGorAG(packednormal, bumpScale);
  142. }
  143.  
  144. half3 BlendNormals(half3 n1, half3 n2)
  145. {
  146. return normalize(half3(n1.xy + n2.xy, n1.z*n2.z));
  147. }
  148.  
  149. half3x3 CreateTangentToWorldPerVertex(half3 normal, half3 tangent, half tangentSign)
  150. {
  151. // For odd-negative scale transforms we need to flip the sign
  152. half sign = tangentSign * unity_WorldTransformParams.w;
  153. half3 binormal = cross(normal, tangent) * sign;
  154. return half3x3(tangent, binormal, normal);
  155. }
  156.  
  157. //-------------------------------------------------------------------------------------
  158. half3 ShadeSHPerVertex (half3 normal, half3 ambient)
  159. {
  160. #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
  161. // Completely per-pixel
  162. // nothing to do here
  163. #elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
  164. // Completely per-vertex
  165. ambient += max(half3(0,0,0), ShadeSH9 (half4(normal, 1.0)));
  166. #else
  167. // L2 per-vertex, L0..L1 & gamma-correction per-pixel
  168.  
  169. // NOTE: SH data is always in Linear AND calculation is split between vertex & pixel
  170. // Convert ambient to Linear and do final gamma-correction at the end (per-pixel)
  171. #ifdef UNITY_COLORSPACE_GAMMA
  172. ambient = GammaToLinearSpace (ambient);
  173. #endif
  174. ambient += SHEvalLinearL2 (half4(normal, 1.0)); // no max since this is only L2 contribution
  175. #endif
  176.  
  177. return ambient;
  178. }
  179.  
  180. half3 ShadeSHPerPixel (half3 normal, half3 ambient, float3 worldPos)
  181. {
  182. half3 ambient_contrib = 0.0;
  183.  
  184. #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
  185. // Completely per-pixel
  186. #if UNITY_LIGHT_PROBE_PROXY_VOLUME
  187. if (unity_ProbeVolumeParams.x == 1.0)
  188. ambient_contrib = SHEvalLinearL0L1_SampleProbeVolume(half4(normal, 1.0), worldPos);
  189. else
  190. ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
  191. #else
  192. ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
  193. #endif
  194.  
  195. ambient_contrib += SHEvalLinearL2(half4(normal, 1.0));
  196.  
  197. ambient += max(half3(0, 0, 0), ambient_contrib);
  198.  
  199. #ifdef UNITY_COLORSPACE_GAMMA
  200. ambient = LinearToGammaSpace(ambient);
  201. #endif
  202. #elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
  203. // Completely per-vertex
  204. // nothing to do here. Gamma conversion on ambient from SH takes place in the vertex shader, see ShadeSHPerVertex.
  205. #else
  206. // L2 per-vertex, L0..L1 & gamma-correction per-pixel
  207. // Ambient in this case is expected to be always Linear, see ShadeSHPerVertex()
  208. #if UNITY_LIGHT_PROBE_PROXY_VOLUME
  209. if (unity_ProbeVolumeParams.x == 1.0)
  210. ambient_contrib = SHEvalLinearL0L1_SampleProbeVolume (half4(normal, 1.0), worldPos);
  211. else
  212. ambient_contrib = SHEvalLinearL0L1 (half4(normal, 1.0));
  213. #else
  214. ambient_contrib = SHEvalLinearL0L1 (half4(normal, 1.0));
  215. #endif
  216.  
  217. ambient = max(half3(0, 0, 0), ambient+ambient_contrib); // include L2 contribution in vertex shader before clamp.
  218. #ifdef UNITY_COLORSPACE_GAMMA
  219. ambient = LinearToGammaSpace (ambient);
  220. #endif
  221. #endif
  222.  
  223. return ambient;
  224. }
  225.  
  226. //-------------------------------------------------------------------------------------
  227. inline float3 BoxProjectedCubemapDirection(float3 worldRefl, float3 worldPos, float4 cubemapCenter, float4 boxMin, float4 boxMax)
  228. {
  229. // Do we have a valid reflection probe?
  230. UNITY_BRANCH
  231. if (cubemapCenter.w > 0.0)
  232. {
  233. float3 nrdir = normalize(worldRefl);
  234.  
  235. #if 1
  236. float3 rbmax = (boxMax.xyz - worldPos) / nrdir;
  237. float3 rbmin = (boxMin.xyz - worldPos) / nrdir;
  238.  
  239. float3 rbminmax = (nrdir > 0.0f) ? rbmax : rbmin;
  240.  
  241. #else // Optimized version
  242. float3 rbmax = (boxMax.xyz - worldPos);
  243. float3 rbmin = (boxMin.xyz - worldPos);
  244.  
  245. float3 select = step (float3(0,0,0), nrdir);
  246. float3 rbminmax = lerp (rbmax, rbmin, select);
  247. rbminmax /= nrdir;
  248. #endif
  249.  
  250. float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
  251.  
  252. worldPos -= cubemapCenter.xyz;
  253. worldRefl = worldPos + nrdir * fa;
  254. }
  255. return worldRefl;
  256. }
  257.  
  258.  
  259. //-------------------------------------------------------------------------------------
  260. // Derivative maps
  261. // http://www.rorydriscoll.com/2012/01/11/derivative-maps/
  262. // For future use.
  263.  
  264. // Project the surface gradient (dhdx, dhdy) onto the surface (n, dpdx, dpdy)
  265. half3 CalculateSurfaceGradient(half3 n, half3 dpdx, half3 dpdy, half dhdx, half dhdy)
  266. {
  267. half3 r1 = cross(dpdy, n);
  268. half3 r2 = cross(n, dpdx);
  269. return (r1 * dhdx + r2 * dhdy) / dot(dpdx, r1);
  270. }
  271.  
  272. // Move the normal away from the surface normal in the opposite surface gradient direction
  273. half3 PerturbNormal(half3 n, half3 dpdx, half3 dpdy, half dhdx, half dhdy)
  274. {
  275. //TODO: normalize seems to be necessary when scales do go beyond the 2...-2 range, should we limit that?
  276. //how expensive is a normalize? Anything cheaper for this case?
  277. return normalize(n - CalculateSurfaceGradient(n, dpdx, dpdy, dhdx, dhdy));
  278. }
  279.  
  280. // Calculate the surface normal using the uv-space gradient (dhdu, dhdv)
  281. half3 CalculateSurfaceNormal(half3 position, half3 normal, half2 gradient, half2 uv)
  282. {
  283. half3 dpdx = ddx(position);
  284. half3 dpdy = ddy(position);
  285.  
  286. half dhdx = dot(gradient, ddx(uv));
  287. half dhdy = dot(gradient, ddy(uv));
  288.  
  289. return PerturbNormal(normal, dpdx, dpdy, dhdx, dhdy);
  290. }
  291.  
  292.  
  293. #endif // UNITY_STANDARD_UTILS_INCLUDED