256 lines
8.9 KiB
HLSL
256 lines
8.9 KiB
HLSL
|
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
|
||
|
// This code in no way belongs to BrainFailProductions. I have just made a small change to make
|
||
|
// it work with texture arrays
|
||
|
|
||
|
|
||
|
#ifndef UNITY_STANDARD_UTILS_INCLUDED
|
||
|
#define UNITY_STANDARD_UTILS_INCLUDED
|
||
|
|
||
|
#include "UnityCG.cginc"
|
||
|
#include "Includes/BatchFewStandardConfig.cginc"
|
||
|
|
||
|
// Helper functions, maybe move into UnityCG.cginc
|
||
|
|
||
|
half SpecularStrength(half3 specular)
|
||
|
{
|
||
|
#if (SHADER_TARGET < 30)
|
||
|
// SM2.0: instruction count limitation
|
||
|
// SM2.0: simplified SpecularStrength
|
||
|
return specular.r; // Red channel - because most metals are either monocrhome or with redish/yellowish tint
|
||
|
#else
|
||
|
return max (max (specular.r, specular.g), specular.b);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Diffuse/Spec Energy conservation
|
||
|
inline half3 EnergyConservationBetweenDiffuseAndSpecular (half3 albedo, half3 specColor, out half oneMinusReflectivity)
|
||
|
{
|
||
|
oneMinusReflectivity = 1 - SpecularStrength(specColor);
|
||
|
#if !UNITY_CONSERVE_ENERGY
|
||
|
return albedo;
|
||
|
#elif UNITY_CONSERVE_ENERGY_MONOCHROME
|
||
|
return albedo * oneMinusReflectivity;
|
||
|
#else
|
||
|
return albedo * (half3(1,1,1) - specColor);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline half OneMinusReflectivityFromMetallic(half metallic)
|
||
|
{
|
||
|
// We'll need oneMinusReflectivity, so
|
||
|
// 1-reflectivity = 1-lerp(dielectricSpec, 1, metallic) = lerp(1-dielectricSpec, 0, metallic)
|
||
|
// store (1-dielectricSpec) in unity_ColorSpaceDielectricSpec.a, then
|
||
|
// 1-reflectivity = lerp(alpha, 0, metallic) = alpha + metallic*(0 - alpha) =
|
||
|
// = alpha - metallic * alpha
|
||
|
half oneMinusDielectricSpec = unity_ColorSpaceDielectricSpec.a;
|
||
|
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
|
||
|
}
|
||
|
|
||
|
inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
||
|
{
|
||
|
specColor = lerp (unity_ColorSpaceDielectricSpec.rgb, albedo, metallic);
|
||
|
oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
|
||
|
return albedo * oneMinusReflectivity;
|
||
|
}
|
||
|
|
||
|
inline half3 PreMultiplyAlpha (half3 diffColor, half alpha, half oneMinusReflectivity, out half outModifiedAlpha)
|
||
|
{
|
||
|
#if defined(_ALPHAPREMULTIPLY_ON)
|
||
|
// NOTE: shader relies on pre-multiply alpha-blend (_SrcBlend = One, _DstBlend = OneMinusSrcAlpha)
|
||
|
|
||
|
// Transparency 'removes' from Diffuse component
|
||
|
diffColor *= alpha;
|
||
|
|
||
|
#if (SHADER_TARGET < 30)
|
||
|
// SM2.0: instruction count limitation
|
||
|
// Instead will sacrifice part of physically based transparency where amount Reflectivity is affecting Transparency
|
||
|
// SM2.0: uses unmodified alpha
|
||
|
outModifiedAlpha = alpha;
|
||
|
#else
|
||
|
// Reflectivity 'removes' from the rest of components, including Transparency
|
||
|
// outAlpha = 1-(1-alpha)*(1-reflectivity) = 1-(oneMinusReflectivity - alpha*oneMinusReflectivity) =
|
||
|
// = 1-oneMinusReflectivity + alpha*oneMinusReflectivity
|
||
|
outModifiedAlpha = 1-oneMinusReflectivity + alpha*oneMinusReflectivity;
|
||
|
#endif
|
||
|
#else
|
||
|
outModifiedAlpha = alpha;
|
||
|
#endif
|
||
|
return diffColor;
|
||
|
}
|
||
|
|
||
|
// Same as ParallaxOffset in Unity CG, except:
|
||
|
// *) precision - half instead of float
|
||
|
half2 ParallaxOffset1Step (half h, half height, half3 viewDir)
|
||
|
{
|
||
|
h = h * height - height/2.0;
|
||
|
half3 v = normalize(viewDir);
|
||
|
v.z += 0.42;
|
||
|
return h * (v.xy / v.z);
|
||
|
}
|
||
|
|
||
|
half LerpOneTo(half b, half t)
|
||
|
{
|
||
|
half oneMinusT = 1 - t;
|
||
|
return oneMinusT + b * t;
|
||
|
}
|
||
|
|
||
|
half3 LerpWhiteTo(half3 b, half t)
|
||
|
{
|
||
|
half oneMinusT = 1 - t;
|
||
|
return half3(oneMinusT, oneMinusT, oneMinusT) + b * t;
|
||
|
}
|
||
|
|
||
|
half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
|
||
|
{
|
||
|
#if defined(UNITY_NO_DXT5nm)
|
||
|
return packednormal.xyz * 2 - 1;
|
||
|
#else
|
||
|
half3 normal;
|
||
|
normal.xy = (packednormal.wy * 2 - 1);
|
||
|
#if (SHADER_TARGET >= 30)
|
||
|
// SM2.0: instruction count limitation
|
||
|
// SM2.0: normal scaler is not supported
|
||
|
normal.xy *= bumpScale;
|
||
|
#endif
|
||
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
||
|
return normal;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
half3 BlendNormals(half3 n1, half3 n2)
|
||
|
{
|
||
|
return normalize(half3(n1.xy + n2.xy, n1.z*n2.z));
|
||
|
}
|
||
|
|
||
|
half3x3 CreateTangentToWorldPerVertex(half3 normal, half3 tangent, half tangentSign)
|
||
|
{
|
||
|
// For odd-negative scale transforms we need to flip the sign
|
||
|
half sign = tangentSign * unity_WorldTransformParams.w;
|
||
|
half3 binormal = cross(normal, tangent) * sign;
|
||
|
return half3x3(tangent, binormal, normal);
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------
|
||
|
half3 ShadeSHPerVertex (half3 normal, half3 ambient)
|
||
|
{
|
||
|
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
|
||
|
// Completely per-pixel
|
||
|
// nothing to do here
|
||
|
#elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
|
||
|
// Completely per-vertex
|
||
|
ambient += max(half3(0,0,0), ShadeSH9 (half4(normal, 1.0)));
|
||
|
#else
|
||
|
// L2 per-vertex, L0..L1 & gamma-correction per-pixel
|
||
|
|
||
|
// NOTE: SH data is always in Linear AND calculation is split between vertex & pixel
|
||
|
// Convert ambient to Linear and do final gamma-correction at the end (per-pixel)
|
||
|
#ifdef UNITY_COLORSPACE_GAMMA
|
||
|
ambient = GammaToLinearSpace (ambient);
|
||
|
#endif
|
||
|
ambient += SHEvalLinearL2 (half4(normal, 1.0)); // no max since this is only L2 contribution
|
||
|
#endif
|
||
|
|
||
|
return ambient;
|
||
|
}
|
||
|
|
||
|
half3 ShadeSHPerPixel (half3 normal, half3 ambient, float3 worldPos)
|
||
|
{
|
||
|
half3 ambient_contrib = 0.0;
|
||
|
|
||
|
#if UNITY_SAMPLE_FULL_SH_PER_PIXEL
|
||
|
// Completely per-pixel
|
||
|
ambient_contrib = ShadeSH9 (half4(normal, 1.0));
|
||
|
ambient += max(half3(0, 0, 0), ambient_contrib);
|
||
|
#elif (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
|
||
|
// Completely per-vertex
|
||
|
// nothing to do here
|
||
|
#else
|
||
|
// L2 per-vertex, L0..L1 & gamma-correction per-pixel
|
||
|
// Ambient in this case is expected to be always Linear, see ShadeSHPerVertex()
|
||
|
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
|
||
|
if (unity_ProbeVolumeParams.x == 1.0)
|
||
|
ambient_contrib = SHEvalLinearL0L1_SampleProbeVolume (half4(normal, 1.0), worldPos);
|
||
|
else
|
||
|
ambient_contrib = SHEvalLinearL0L1 (half4(normal, 1.0));
|
||
|
#else
|
||
|
ambient_contrib = SHEvalLinearL0L1 (half4(normal, 1.0));
|
||
|
#endif
|
||
|
|
||
|
ambient = max(half3(0, 0, 0), ambient+ambient_contrib); // include L2 contribution in vertex shader before clamp.
|
||
|
#ifdef UNITY_COLORSPACE_GAMMA
|
||
|
ambient = LinearToGammaSpace (ambient);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return ambient;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------------------
|
||
|
inline half3 BoxProjectedCubemapDirection (half3 worldRefl, float3 worldPos, float4 cubemapCenter, float4 boxMin, float4 boxMax)
|
||
|
{
|
||
|
// Do we have a valid reflection probe?
|
||
|
UNITY_BRANCH
|
||
|
if (cubemapCenter.w > 0.0)
|
||
|
{
|
||
|
half3 nrdir = normalize(worldRefl);
|
||
|
|
||
|
#if 1
|
||
|
half3 rbmax = (boxMax.xyz - worldPos) / nrdir;
|
||
|
half3 rbmin = (boxMin.xyz - worldPos) / nrdir;
|
||
|
|
||
|
half3 rbminmax = (nrdir > 0.0f) ? rbmax : rbmin;
|
||
|
|
||
|
#else // Optimized version
|
||
|
half3 rbmax = (boxMax.xyz - worldPos);
|
||
|
half3 rbmin = (boxMin.xyz - worldPos);
|
||
|
|
||
|
half3 select = step (half3(0,0,0), nrdir);
|
||
|
half3 rbminmax = lerp (rbmax, rbmin, select);
|
||
|
rbminmax /= nrdir;
|
||
|
#endif
|
||
|
|
||
|
half fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
|
||
|
|
||
|
worldPos -= cubemapCenter.xyz;
|
||
|
worldRefl = worldPos + nrdir * fa;
|
||
|
}
|
||
|
return worldRefl;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------------------
|
||
|
// Derivative maps
|
||
|
// http://www.rorydriscoll.com/2012/01/11/derivative-maps/
|
||
|
// For future use.
|
||
|
|
||
|
// Project the surface gradient (dhdx, dhdy) onto the surface (n, dpdx, dpdy)
|
||
|
half3 CalculateSurfaceGradient(half3 n, half3 dpdx, half3 dpdy, half dhdx, half dhdy)
|
||
|
{
|
||
|
half3 r1 = cross(dpdy, n);
|
||
|
half3 r2 = cross(n, dpdx);
|
||
|
return (r1 * dhdx + r2 * dhdy) / dot(dpdx, r1);
|
||
|
}
|
||
|
|
||
|
// Move the normal away from the surface normal in the opposite surface gradient direction
|
||
|
half3 PerturbNormal(half3 n, half3 dpdx, half3 dpdy, half dhdx, half dhdy)
|
||
|
{
|
||
|
//TODO: normalize seems to be necessary when scales do go beyond the 2...-2 range, should we limit that?
|
||
|
//how expensive is a normalize? Anything cheaper for this case?
|
||
|
return normalize(n - CalculateSurfaceGradient(n, dpdx, dpdy, dhdx, dhdy));
|
||
|
}
|
||
|
|
||
|
// Calculate the surface normal using the uv-space gradient (dhdu, dhdv)
|
||
|
half3 CalculateSurfaceNormal(half3 position, half3 normal, half2 gradient, half2 uv)
|
||
|
{
|
||
|
half3 dpdx = ddx(position);
|
||
|
half3 dpdy = ddy(position);
|
||
|
|
||
|
half dhdx = dot(gradient, ddx(uv));
|
||
|
half dhdy = dot(gradient, ddy(uv));
|
||
|
|
||
|
return PerturbNormal(normal, dpdx, dpdy, dhdx, dhdy);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif // UNITY_STANDARD_UTILS_INCLUDED
|