284 lines
10 KiB
HLSL

// OpenLit Library 1.0.2
// This code is licensed under CC0 1.0 Universal.
// https://creativecommons.org/publicdomain/zero/1.0/
#if !defined(OPENLIT_CORE_INCLUDED)
#define OPENLIT_CORE_INCLUDED
//------------------------------------------------------------------------------------------------------------------------------
// Macro
#define OPENLIT_LIGHT_COLOR _LightColor0.rgb
#define OPENLIT_LIGHT_DIRECTION _WorldSpaceLightPos0.xyz
#define OPENLIT_MATRIX_M unity_ObjectToWorld
#define OPENLIT_FALLBACK_DIRECTION float4(0.001,0.002,0.001,0)
//------------------------------------------------------------------------------------------------------------------------------
// SRGB <-> Linear
float3 OpenLitLinearToSRGB(float3 col)
{
return LinearToGammaSpace(col);
}
float3 OpenLitSRGBToLinear(float3 col)
{
return GammaToLinearSpace(col);
}
//------------------------------------------------------------------------------------------------------------------------------
// Color
float OpenLitLuminance(float3 rgb)
{
#if defined(UNITY_COLORSPACE_GAMMA)
return dot(rgb, float3(0.22, 0.707, 0.071));
#else
return dot(rgb, float3(0.0396819152, 0.458021790, 0.00609653955));
#endif
}
float OpenLitGray(float3 rgb)
{
return dot(rgb, float3(1.0/3.0, 1.0/3.0, 1.0/3.0));
}
//------------------------------------------------------------------------------------------------------------------------------
// Structure
struct OpenLitLightDatas
{
float3 lightDirection;
float3 directLight;
float3 indirectLight;
};
//------------------------------------------------------------------------------------------------------------------------------
// Light Direction
// Use `UnityWorldSpaceLightDir(float3 positionWS)` for ForwardAdd passes
float3 ComputeCustomLightDirection(float4 lightDirectionOverride)
{
float3 customDir = length(lightDirectionOverride.xyz) * normalize(mul((float3x3)OPENLIT_MATRIX_M, lightDirectionOverride.xyz));
return lightDirectionOverride.w ? customDir : lightDirectionOverride.xyz;
}
void ComputeLightDirection(out float3 lightDirection, out float3 lightDirectionForSH9, float4 lightDirectionOverride)
{
float3 mainDir = OPENLIT_LIGHT_DIRECTION * OpenLitLuminance(OPENLIT_LIGHT_COLOR);
#if !defined(LIGHTMAP_ON) && UNITY_SHOULD_SAMPLE_SH
float3 sh9Dir = unity_SHAr.xyz * 0.333333 + unity_SHAg.xyz * 0.333333 + unity_SHAb.xyz * 0.333333;
float3 sh9DirAbs = float3(sh9Dir.x, abs(sh9Dir.y), sh9Dir.z);
#else
float3 sh9Dir = 0;
float3 sh9DirAbs = 0;
#endif
float3 customDir = ComputeCustomLightDirection(lightDirectionOverride);
lightDirection = normalize(sh9DirAbs + mainDir + customDir);
lightDirectionForSH9 = sh9Dir + mainDir;
lightDirectionForSH9 = dot(lightDirectionForSH9,lightDirectionForSH9) < 0.000001 ? 0 : normalize(lightDirectionForSH9);
}
void ComputeLightDirection(out float3 lightDirection, out float3 lightDirectionForSH9)
{
ComputeLightDirection(lightDirection, lightDirectionForSH9, OPENLIT_FALLBACK_DIRECTION);
}
//------------------------------------------------------------------------------------------------------------------------------
// ShadeSH9
void ShadeSH9ToonDouble(float3 lightDirection, out float3 shMax, out float3 shMin)
{
#if !defined(LIGHTMAP_ON) && UNITY_SHOULD_SAMPLE_SH
float3 N = lightDirection * 0.666666;
float4 vB = N.xyzz * N.yzzx;
// L0 L2
float3 res = float3(unity_SHAr.w,unity_SHAg.w,unity_SHAb.w);
res.r += dot(unity_SHBr, vB);
res.g += dot(unity_SHBg, vB);
res.b += dot(unity_SHBb, vB);
res += unity_SHC.rgb * (N.x * N.x - N.y * N.y);
// L1
float3 l1;
l1.r = dot(unity_SHAr.rgb, N);
l1.g = dot(unity_SHAg.rgb, N);
l1.b = dot(unity_SHAb.rgb, N);
shMax = res + l1;
shMin = res - l1;
#if defined(UNITY_COLORSPACE_GAMMA)
shMax = OpenLitLinearToSRGB(shMax);
shMin = OpenLitLinearToSRGB(shMin);
#endif
#else
shMax = 0.0;
shMin = 0.0;
#endif
}
void ShadeSH9ToonDouble(out float3 shMax, out float3 shMin)
{
float3 lightDirection, lightDirectionForSH9;
ComputeLightDirection(lightDirection, lightDirectionForSH9, OPENLIT_FALLBACK_DIRECTION);
ShadeSH9ToonDouble(lightDirectionForSH9, shMax, shMin);
}
float3 ShadeSH9Toon()
{
float3 shMax, shMin;
ShadeSH9ToonDouble(shMax, shMin);
return shMax;
}
float3 ShadeSH9ToonIndirect()
{
float3 shMax, shMin;
ShadeSH9ToonDouble(shMax, shMin);
return shMin;
}
//------------------------------------------------------------------------------------------------------------------------------
// Lighting
void ComputeSHLightsAndDirection(out float3 lightDirection, out float3 directLight, out float3 indirectLight, float4 lightDirectionOverride)
{
float3 lightDirectionForSH9;
ComputeLightDirection(lightDirection, lightDirectionForSH9, lightDirectionOverride);
ShadeSH9ToonDouble(lightDirectionForSH9, directLight, indirectLight);
}
void ComputeSHLightsAndDirection(out float3 lightDirection, out float3 directLight, out float3 indirectLight)
{
ComputeSHLightsAndDirection(lightDirection, directLight, indirectLight, OPENLIT_FALLBACK_DIRECTION);
}
void ComputeLights(out float3 lightDirection, out float3 directLight, out float3 indirectLight, float4 lightDirectionOverride)
{
ComputeSHLightsAndDirection(lightDirection, directLight, indirectLight, lightDirectionOverride);
directLight += OPENLIT_LIGHT_COLOR;
}
void ComputeLights(out float3 lightDirection, out float3 directLight, out float3 indirectLight)
{
ComputeSHLightsAndDirection(lightDirection, directLight, indirectLight);
directLight += OPENLIT_LIGHT_COLOR;
}
void ComputeLights(out OpenLitLightDatas lightDatas, float4 lightDirectionOverride)
{
ComputeLights(lightDatas.lightDirection, lightDatas.directLight, lightDatas.indirectLight, lightDirectionOverride);
}
void ComputeLights(out OpenLitLightDatas lightDatas)
{
ComputeLights(lightDatas.lightDirection, lightDatas.directLight, lightDatas.indirectLight);
}
//------------------------------------------------------------------------------------------------------------------------------
// Correct
void CorrectLights(inout OpenLitLightDatas lightDatas, float lightMinLimit, float lightMaxLimit, float monochromeLighting, float asUnlit)
{
lightDatas.directLight = clamp(lightDatas.directLight, lightMinLimit, lightMaxLimit);
lightDatas.directLight = lerp(lightDatas.directLight, OpenLitGray(lightDatas.directLight), monochromeLighting);
lightDatas.directLight = lerp(lightDatas.directLight, 1.0, asUnlit);
lightDatas.indirectLight = clamp(lightDatas.indirectLight, 0.0, lightMaxLimit);
}
//------------------------------------------------------------------------------------------------------------------------------
// Vertex Lighting
float3 ComputeAdditionalLights(float3 positionWS, float3 positionCS)
{
float4 toLightX = unity_4LightPosX0 - positionWS.x;
float4 toLightY = unity_4LightPosY0 - positionWS.y;
float4 toLightZ = unity_4LightPosZ0 - positionWS.z;
float4 lengthSq = toLightX * toLightX + 0.000001;
lengthSq += toLightY * toLightY;
lengthSq += toLightZ * toLightZ;
//float4 atten = 1.0 / (1.0 + lengthSq * unity_4LightAtten0);
float4 atten = saturate(saturate((25.0 - lengthSq * unity_4LightAtten0) * 0.111375) / (0.987725 + lengthSq * unity_4LightAtten0));
float3 additionalLightColor;
additionalLightColor = unity_LightColor[0].rgb * atten.x;
additionalLightColor = additionalLightColor + unity_LightColor[1].rgb * atten.y;
additionalLightColor = additionalLightColor + unity_LightColor[2].rgb * atten.z;
additionalLightColor = additionalLightColor + unity_LightColor[3].rgb * atten.w;
return additionalLightColor;
}
//------------------------------------------------------------------------------------------------------------------------------
// Encode and decode
#if !defined(SHADER_API_GLES)
// -1 - 1
uint EncodeNormalizedFloat3ToUint(float3 vec)
{
uint valx = abs(vec.x) >= 1 ? 511 : abs(vec.x) * 511;
uint valy = abs(vec.y) >= 1 ? 511 : abs(vec.y) * 511;
uint valz = abs(vec.z) >= 1 ? 511 : abs(vec.z) * 511;
valx = valx & 0x000001ffu;
valy = valy & 0x000001ffu;
valz = valz & 0x000001ffu;
valx += vec.x > 0 ? 0 : 512;
valy += vec.y > 0 ? 0 : 512;
valz += vec.z > 0 ? 0 : 512;
valy = valy << 10;
valz = valz << 20;
return valx | valy | valz;
}
float3 DecodeNormalizedFloat3FromUint(uint val)
{
// 5 math in target 5.0
uint3 val3 = val >> uint3(0,10,20);
float3 vec = val3 & 0x000001ffu;
vec /= (val3 & 0x00000200u) == 0x00000200u ? -511.0 : 511.0;
return vec;
}
// 0 - 999
uint EncodeHDRColorToUint(float3 col)
{
col = clamp(col, 0, 999);
float maxcol = max(col.r,max(col.g,col.b));
float floatDigit = maxcol == 0 ? 0 : log10(maxcol);
uint digit = floatDigit >= 0 ? floatDigit + 1 : 0;
if(digit > 3) digit = 3;
float scale = pow(10,digit);
col /= scale;
uint R = col.r * 1023;
uint G = col.g * 1023;
uint B = col.b * 1023;
uint M = digit;
R = R & 0x000003ffu;
G = G & 0x000003ffu;
B = B & 0x000003ffu;
G = G << 10;
B = B << 20;
M = M << 30;
return R | G | B | M;
}
float3 DecodeHDRColorFromUint(uint val)
{
// 5 math in target 5.0
uint4 RGBM = val >> uint4(0,10,20,30);
return float3(RGBM.rgb & 0x000003ffu) / 1023.0 * pow(10,RGBM.a);
}
void PackLightDatas(out uint3 pack, OpenLitLightDatas lightDatas)
{
pack = uint3(
EncodeNormalizedFloat3ToUint(lightDatas.lightDirection),
EncodeHDRColorToUint(lightDatas.directLight),
EncodeHDRColorToUint(lightDatas.indirectLight)
);
}
void UnpackLightDatas(out OpenLitLightDatas lightDatas, uint3 pack)
{
lightDatas.lightDirection = DecodeNormalizedFloat3FromUint(pack.x);
lightDatas.directLight = DecodeHDRColorFromUint(pack.y);
lightDatas.indirectLight = DecodeHDRColorFromUint(pack.z);
}
#endif // #if !defined(SHADER_API_GLES)
#endif // #if !defined(OPENLIT_CORE_INCLUDED)