rabidus-test/Assets/PolyFew/BatchFewShader/Includes/BatchFewStandardUtils.cginc

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