1114 lines
41 KiB
HLSL
1114 lines
41 KiB
HLSL
#ifndef LIL_FUNCTIONS_INCLUDED
|
|
#define LIL_FUNCTIONS_INCLUDED
|
|
|
|
#include "lil_common_functions_thirdparty.hlsl"
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Math
|
|
|
|
// Tooning
|
|
#if LIL_ANTIALIAS_MODE == 0
|
|
float lilIsIn0to1(float f)
|
|
{
|
|
return saturate(f) == f;
|
|
}
|
|
|
|
float lilIsIn0to1(float f, float nv)
|
|
{
|
|
return saturate(f) == f;
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border)
|
|
{
|
|
return step(border, value);
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border, float blur)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin);
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border, float blur, float borderRange)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5 - borderRange);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin);
|
|
}
|
|
|
|
float lilTooning(float value, float border)
|
|
{
|
|
return lilTooningNoSaturate(value, border);
|
|
}
|
|
|
|
float lilTooning(float value, float border, float blur)
|
|
{
|
|
return saturate(lilTooningNoSaturate(value, border, blur));
|
|
}
|
|
|
|
float lilTooning(float value, float border, float blur, float borderRange)
|
|
{
|
|
return saturate(lilTooningNoSaturate(value, border, blur, borderRange));
|
|
}
|
|
#else
|
|
float lilIsIn0to1(float f)
|
|
{
|
|
float value = 0.5 - abs(f-0.5);
|
|
return saturate(value / clamp(fwidth(value), 0.0001, 1.0));
|
|
}
|
|
|
|
float lilIsIn0to1(float f, float nv)
|
|
{
|
|
float value = 0.5 - abs(f-0.5);
|
|
return saturate(value / clamp(fwidth(value), 0.0001, nv));
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border)
|
|
{
|
|
return (value - border) / clamp(fwidth(value), 0.0001, 1.0);
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border, float blur)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin + fwidth(value));
|
|
}
|
|
|
|
float lilTooningNoSaturate(float value, float border, float blur, float borderRange)
|
|
{
|
|
float borderMin = saturate(border - blur * 0.5 - borderRange);
|
|
float borderMax = saturate(border + blur * 0.5);
|
|
return (value - borderMin) / saturate(borderMax - borderMin + fwidth(value));
|
|
}
|
|
|
|
float lilTooning(float value, float border)
|
|
{
|
|
return saturate(lilTooningNoSaturate(value, border));
|
|
}
|
|
|
|
float lilTooning(float value, float border, float blur)
|
|
{
|
|
return saturate(lilTooningNoSaturate(value, border, blur));
|
|
}
|
|
|
|
float lilTooning(float value, float border, float blur, float borderRange)
|
|
{
|
|
return saturate(lilTooningNoSaturate(value, border, blur, borderRange));
|
|
}
|
|
#endif
|
|
|
|
// Optimized matrix calculation
|
|
float4 lilOptMul(float4x4 mat, float3 pos)
|
|
{
|
|
return mat._m00_m10_m20_m30 * pos.x + (mat._m01_m11_m21_m31 * pos.y + (mat._m02_m12_m22_m32 * pos.z + mat._m03_m13_m23_m33));
|
|
}
|
|
|
|
// Check if the value is within range
|
|
float lilIsIn0to1(float2 f)
|
|
{
|
|
return lilIsIn0to1(f.x) * lilIsIn0to1(f.y);
|
|
}
|
|
|
|
float lilIsIn0to1(float2 f, float nv)
|
|
{
|
|
return lilIsIn0to1(f.x, nv) * lilIsIn0to1(f.y, nv);
|
|
}
|
|
|
|
// Normal blend in tangent space
|
|
float3 lilBlendNormal(float3 dstNormal, float3 srcNormal)
|
|
{
|
|
return float3(dstNormal.xy + srcNormal.xy, dstNormal.z * srcNormal.z);
|
|
}
|
|
|
|
float lilMedian(float r, float g, float b)
|
|
{
|
|
return max(min(r, g), min(max(r, g), b));
|
|
}
|
|
|
|
float lilMSDF(float3 msd)
|
|
{
|
|
float sd = lilMedian(msd.r, msd.g, msd.b);
|
|
return saturate((sd - 0.5)/clamp(fwidth(sd), 0.01, 1.0));
|
|
}
|
|
|
|
float lilIntervalTime(float interval)
|
|
{
|
|
return floor(LIL_TIME / interval) * interval;
|
|
}
|
|
|
|
float lilNsqDistance(float2 a, float2 b)
|
|
{
|
|
return dot(a-b,a-b);
|
|
}
|
|
|
|
float3 lilOrthoNormalize(float3 tangent, float3 normal)
|
|
{
|
|
return normalize(tangent - normal * dot(normal, tangent));
|
|
}
|
|
|
|
float3 lilUnpackNormalScale(float4 normalTex, float scale)
|
|
{
|
|
float3 normal;
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
normal = normalTex.rgb * 2.0 - 1.0;
|
|
normal.xy *= scale;
|
|
#else
|
|
#if !defined(UNITY_ASTC_NORMALMAP_ENCODING)
|
|
normalTex.a *= normalTex.r;
|
|
#endif
|
|
normal.xy = normalTex.ag * 2.0 - 1.0;
|
|
normal.xy *= scale;
|
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
|
#endif
|
|
return normal;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Position Transform
|
|
struct lilVertexPositionInputs
|
|
{
|
|
float3 positionWS; // World space
|
|
float3 positionVS; // View space
|
|
float4 positionCS; // Clip space
|
|
float4 positionSS; // Screen space
|
|
};
|
|
|
|
lilVertexPositionInputs lilGetVertexPositionInputs(float4 positionOS)
|
|
{
|
|
lilVertexPositionInputs output;
|
|
output.positionWS = lilTransformOStoWS(positionOS);
|
|
output.positionVS = lilTransformWStoVS(output.positionWS);
|
|
output.positionCS = lilTransformWStoCS(output.positionWS);
|
|
output.positionSS = lilTransformCStoSS(output.positionCS);
|
|
return output;
|
|
}
|
|
|
|
lilVertexPositionInputs lilGetVertexPositionInputs(float3 positionOS)
|
|
{
|
|
return lilGetVertexPositionInputs(float4(positionOS, 1.0));
|
|
}
|
|
|
|
lilVertexPositionInputs lilReGetVertexPositionInputs(lilVertexPositionInputs output)
|
|
{
|
|
output.positionVS = lilTransformWStoVS(output.positionWS);
|
|
output.positionCS = lilTransformWStoCS(output.positionWS);
|
|
output.positionSS = lilTransformCStoSS(output.positionCS);
|
|
return output;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Normal Transform
|
|
struct lilVertexNormalInputs
|
|
{
|
|
float3 tangentWS;
|
|
float3 bitangentWS;
|
|
float3 normalWS;
|
|
};
|
|
|
|
lilVertexNormalInputs lilGetVertexNormalInputs()
|
|
{
|
|
lilVertexNormalInputs output;
|
|
output.normalWS = float3(1.0, 0.0, 0.0);
|
|
output.tangentWS = float3(1.0, 0.0, 0.0);
|
|
output.bitangentWS = float3(0.0, 1.0, 0.0);
|
|
return output;
|
|
}
|
|
|
|
lilVertexNormalInputs lilGetVertexNormalInputs(float3 normalOS)
|
|
{
|
|
lilVertexNormalInputs output;
|
|
output.normalWS = lilTransformNormalOStoWS(normalOS, true);
|
|
output.tangentWS = float3(1.0, 0.0, 0.0);
|
|
output.bitangentWS = float3(0.0, 1.0, 0.0);
|
|
return output;
|
|
}
|
|
|
|
lilVertexNormalInputs lilGetVertexNormalInputs(float3 normalOS, float4 tangentOS)
|
|
{
|
|
lilVertexNormalInputs output;
|
|
output.normalWS = lilTransformNormalOStoWS(normalOS, true);
|
|
output.tangentWS = lilTransformDirOStoWS(tangentOS.xyz, true);
|
|
output.bitangentWS = cross(output.normalWS, output.tangentWS) * (tangentOS.w * LIL_NEGATIVE_SCALE);
|
|
return output;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Outline
|
|
float lilGetOutlineWidth(float2 uv, float4 color, float outlineWidth, TEXTURE2D(outlineWidthMask), uint outlineVertexR2Width LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
outlineWidth *= 0.01;
|
|
#if defined(LIL_FEATURE_OutlineWidthMask)
|
|
outlineWidth *= LIL_SAMPLE_2D_LOD(outlineWidthMask, samp, uv, 0).r;
|
|
#endif
|
|
if(outlineVertexR2Width == 1) outlineWidth *= color.r;
|
|
if(outlineVertexR2Width == 2) outlineWidth *= color.a;
|
|
return outlineWidth;
|
|
}
|
|
|
|
float lilGetOutlineWidth(float3 positionOS, float3 positionWS, float2 uv, float4 color, float outlineWidth, TEXTURE2D(outlineWidthMask), uint outlineVertexR2Width, float outlineFixWidth LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
outlineWidth = lilGetOutlineWidth(uv, color, outlineWidth, outlineWidthMask, outlineVertexR2Width LIL_SAMP_IN(samp));
|
|
outlineWidth *= lerp(1.0, saturate(length(lilHeadDirection(positionWS))), outlineFixWidth);
|
|
return outlineWidth;
|
|
}
|
|
|
|
float3 lilGetOutlineVector(float3x3 tbnOS, float2 uv, float outlineVectorScale, TEXTURE2D(outlineVectorTex) LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
float3 outlineVector = lilUnpackNormalScale(LIL_SAMPLE_2D_LOD(outlineVectorTex, samp, uv, 0), outlineVectorScale);
|
|
outlineVector = mul(outlineVector, tbnOS);
|
|
return outlineVector;
|
|
}
|
|
|
|
void lilCalcOutlinePosition(inout float3 positionOS, float2 uvs[4], float4 color, float3 normalOS, float3x3 tbnOS, float outlineWidth, TEXTURE2D(outlineWidthMask), uint outlineVertexR2Width, float outlineFixWidth, float outlineZBias, float outlineVectorScale, uint outlineVectorUVMode, TEXTURE2D(outlineVectorTex) LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
float3 positionWS = lilToAbsolutePositionWS(lilOptMul(LIL_MATRIX_M, positionOS).xyz);
|
|
float width = lilGetOutlineWidth(positionOS, positionWS, uvs[0], color, outlineWidth, outlineWidthMask, outlineVertexR2Width, outlineFixWidth LIL_SAMP_IN(samp));
|
|
float3 outlineN = normalOS;
|
|
#if defined(LIL_FEATURE_OutlineVectorTex)
|
|
outlineN = lilGetOutlineVector(tbnOS, uvs[outlineVectorUVMode], outlineVectorScale, outlineVectorTex LIL_SAMP_IN(samp));
|
|
#endif
|
|
if(outlineVertexR2Width == 2) outlineN = mul(color.rgb * 2.0 - 1.0, tbnOS);
|
|
positionOS += outlineN * width;
|
|
float3 V = lilIsPerspective() ? lilViewDirectionOS(positionOS) : mul((float3x3)LIL_MATRIX_I_M, LIL_MATRIX_V._m20_m21_m22);
|
|
positionOS -= normalize(V) * outlineZBias;
|
|
}
|
|
|
|
void lilCalcOutlinePositionLite(inout float3 positionOS, float2 uv, float4 color, float3 normalOS, float3x3 tbnOS, float outlineWidth, TEXTURE2D(outlineWidthMask), uint outlineVertexR2Width, float outlineFixWidth, float outlineZBias LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
float3 positionWS = lilToAbsolutePositionWS(lilOptMul(LIL_MATRIX_M, positionOS).xyz);
|
|
float width = lilGetOutlineWidth(positionOS, positionWS, uv, color, outlineWidth, outlineWidthMask, outlineVertexR2Width, outlineFixWidth LIL_SAMP_IN(samp));
|
|
float3 outlineN = normalOS;
|
|
if(outlineVertexR2Width == 2) outlineN = mul(color.rgb * 2.0 - 1.0, tbnOS);
|
|
positionOS += outlineN * width;
|
|
float3 V = lilIsPerspective() ? lilViewDirectionOS(positionOS) : mul((float3x3)LIL_MATRIX_I_M, LIL_MATRIX_V._m20_m21_m22);
|
|
positionOS -= normalize(V) * outlineZBias;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Color
|
|
float3 lilBlendColor(float3 dstCol, float3 srcCol, float3 srcA, uint blendMode)
|
|
{
|
|
float3 ad = dstCol + srcCol;
|
|
float3 mu = dstCol * srcCol;
|
|
float3 outCol;
|
|
if(blendMode == 0) outCol = srcCol; // Normal
|
|
if(blendMode == 1) outCol = ad; // Add
|
|
if(blendMode == 2) outCol = max(ad - mu, dstCol); // Screen
|
|
if(blendMode == 3) outCol = mu; // Multiply
|
|
return lerp(dstCol, outCol, srcA);
|
|
}
|
|
|
|
float3 lilBlendColor(float3 dstCol, float3 srcCol, float srcA, uint blendMode)
|
|
{
|
|
return lilBlendColor(dstCol, srcCol, float3(srcA,srcA,srcA), blendMode);
|
|
}
|
|
|
|
float lilGray(float3 rgb)
|
|
{
|
|
return dot(rgb, float3(1.0/3.0, 1.0/3.0, 1.0/3.0));
|
|
}
|
|
|
|
float3 lilToneCorrection(float3 c, float4 hsvg)
|
|
{
|
|
// gamma
|
|
c = pow(abs(c), hsvg.w);
|
|
// rgb -> hsv
|
|
float4 p = (c.b > c.g) ? float4(c.bg,-1.0,2.0/3.0) : float4(c.gb,0.0,-1.0/3.0);
|
|
float4 q = (p.x > c.r) ? float4(p.xyw, c.r) : float4(c.r, p.yzx);
|
|
float d = q.x - min(q.w, q.y);
|
|
float e = 1.0e-10;
|
|
float3 hsv = float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
|
// shift
|
|
hsv = float3(hsv.x+hsvg.x,saturate(hsv.y*hsvg.y),saturate(hsv.z*hsvg.z));
|
|
// hsv -> rgb
|
|
return hsv.z - hsv.z * hsv.y + hsv.z * hsv.y * saturate(abs(frac(hsv.x + float3(1.0, 2.0/3.0, 1.0/3.0)) * 6.0 - 3.0) - 1.0);
|
|
}
|
|
|
|
float3 lilGradationMap(float3 col, TEXTURE2D(gradationMap), float strength)
|
|
{
|
|
if(strength == 0.0) return col;
|
|
#if !defined(LIL_COLORSPACE_GAMMA)
|
|
col = lilLinearToSRGB(col);
|
|
#endif
|
|
float R = LIL_SAMPLE_1D(gradationMap, sampler_linear_clamp, col.r).r;
|
|
float G = LIL_SAMPLE_1D(gradationMap, sampler_linear_clamp, col.g).g;
|
|
float B = LIL_SAMPLE_1D(gradationMap, sampler_linear_clamp, col.b).b;
|
|
float3 outrgb = float3(R,G,B);
|
|
#if !defined(LIL_COLORSPACE_GAMMA)
|
|
col = lilSRGBToLinear(col);
|
|
outrgb = lilSRGBToLinear(outrgb);
|
|
#endif
|
|
return lerp(col, outrgb, strength);
|
|
}
|
|
|
|
float3 lilDecodeHDR(float4 data, float4 hdr)
|
|
{
|
|
float alpha = hdr.w * (data.a - 1.0) + 1.0;
|
|
|
|
#if defined(LIL_COLORSPACE_GAMMA)
|
|
return (hdr.x * alpha) * data.rgb;
|
|
#elif defined(UNITY_USE_NATIVE_HDR)
|
|
return hdr.x * data.rgb;
|
|
#else
|
|
return (hdr.x * pow(abs(alpha), hdr.y)) * data.rgb;
|
|
#endif
|
|
}
|
|
|
|
void lilCalcLUTUV(float3 col, float resX, float resY, inout float4 uv, inout float factor)
|
|
{
|
|
#if !defined(UNITY_COLORSPACE_GAMMA)
|
|
col = lilLinearToSRGB(col);
|
|
#endif
|
|
float3 res = float3(resX, resY, resX * resY);
|
|
float3 resInv = float3(1.0, -1.0, 1.0) / res;
|
|
|
|
float3 col2 = (col - col * resInv.z) + 0.5 * resInv.z;
|
|
float4 b2 = saturate(col2.b + resInv.z * float2(-0.5, 0.5)).xxyy * res.zyzy;
|
|
float4 b3 = floor(b2);
|
|
uv = float4(0,1,0,1) + (col2.rgrg + b3) * resInv.xyxy;
|
|
factor = abs(b2.x - b3.x);
|
|
}
|
|
|
|
float4 lilSampleLUT(float4 uv, float factor, TEXTURE2D(lutTex))
|
|
{
|
|
float4 a = LIL_SAMPLE_2D_LOD(lutTex, sampler_linear_clamp, uv.xy, 0);
|
|
float4 b = LIL_SAMPLE_2D_LOD(lutTex, sampler_linear_clamp, uv.zw, 0);
|
|
return lerp(a, b, factor);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// UV
|
|
|
|
// Rotation
|
|
float2 lilRotateUV(float2 uv, float2x2 rotMatrix)
|
|
{
|
|
return mul(rotMatrix, uv - 0.5) + 0.5;
|
|
}
|
|
|
|
float2 lilRotateUV(float2 uv, float angle)
|
|
{
|
|
float si,co;
|
|
sincos(angle, si, co);
|
|
float2 outuv = uv - 0.5;
|
|
outuv = float2(
|
|
outuv.x * co - outuv.y * si,
|
|
outuv.x * si + outuv.y * co
|
|
);
|
|
outuv += 0.5;
|
|
return outuv;
|
|
}
|
|
|
|
// Tiling, offset, animation calculations
|
|
float2 lilCalcUV(float2 uv, float4 uv_st)
|
|
{
|
|
return uv * uv_st.xy + uv_st.zw;
|
|
}
|
|
|
|
float2 lilCalcUV(float2 uv, float4 uv_st, float angle)
|
|
{
|
|
float2 outuv = uv * uv_st.xy + uv_st.zw;
|
|
outuv = lilRotateUV(outuv, angle);
|
|
return outuv;
|
|
}
|
|
|
|
float2 lilCalcUV(float2 uv, float4 uv_st, float2 uv_sr)
|
|
{
|
|
return uv * uv_st.xy + uv_st.zw + frac(uv_sr * LIL_TIME);
|
|
}
|
|
|
|
float2 lilCalcUV(float2 uv, float4 uv_st, float4 uv_sr)
|
|
{
|
|
float2 outuv = uv * uv_st.xy + uv_st.zw;
|
|
outuv = lilRotateUV(outuv, uv_sr.z + uv_sr.w * LIL_TIME) + frac(uv_sr.xy * LIL_TIME);
|
|
return outuv;
|
|
}
|
|
|
|
float2 lilCalcUVWithoutAnimation(float2 uv, float4 uv_st, float4 uv_sr)
|
|
{
|
|
return lilRotateUV(uv * uv_st.xy + uv_st.zw, uv_sr.z);
|
|
}
|
|
|
|
float2 lilCalcDoubleSideUV(float2 uv, float facing, float shiftBackfaceUV)
|
|
{
|
|
return facing < (shiftBackfaceUV-1.0) ? uv + float2(1.0,0.0) : uv;
|
|
}
|
|
|
|
// Decal
|
|
float2 lilCalcDecalUV(
|
|
float2 uv,
|
|
float4 uv_ST,
|
|
float angle,
|
|
bool isLeftOnly,
|
|
bool isRightOnly,
|
|
bool shouldCopy,
|
|
bool shouldFlipMirror,
|
|
bool shouldFlipCopy,
|
|
bool isRightHand)
|
|
{
|
|
float2 outUV = uv;
|
|
|
|
// Copy
|
|
if(shouldCopy) outUV.x = abs(outUV.x - 0.5) + 0.5;
|
|
|
|
// Scale & Offset
|
|
outUV = outUV * uv_ST.xy + uv_ST.zw;
|
|
|
|
// Flip
|
|
if(shouldFlipCopy && uv.x<0.5) outUV.x = 1.0 - outUV.x;
|
|
if(shouldFlipMirror && isRightHand) outUV.x = 1.0 - outUV.x;
|
|
|
|
// Hide
|
|
if(isLeftOnly && isRightHand) outUV.x = -1.0;
|
|
if(isRightOnly && !isRightHand) outUV.x = -1.0;
|
|
|
|
// Rotate
|
|
outUV = (outUV - uv_ST.zw) / uv_ST.xy;
|
|
outUV = lilRotateUV(outUV, angle);
|
|
outUV = outUV * uv_ST.xy + uv_ST.zw;
|
|
|
|
return outUV;
|
|
}
|
|
|
|
float2 lilCalcAtlasAnimation(float2 uv, float4 decalAnimation, float4 decalSubParam)
|
|
{
|
|
float2 outuv = lerp(float2(uv.x, 1.0-uv.y), 0.5, decalSubParam.z);
|
|
uint animTime = (uint)(LIL_TIME * decalAnimation.w) % (uint)decalAnimation.z;
|
|
uint offsetX = animTime % (uint)decalAnimation.x;
|
|
uint offsetY = animTime / (uint)decalAnimation.x;
|
|
outuv = (outuv + float2(offsetX,offsetY)) * decalSubParam.xy / decalAnimation.xy;
|
|
outuv.y = 1.0-outuv.y;
|
|
return outuv;
|
|
}
|
|
|
|
// MatCap
|
|
float2 lilCalcMatCapUV(float2 uv1, float3 normalWS, float3 viewDirection, float3 headDirection, float4 matcap_ST, float2 matcapBlendUV1, bool zRotCancel, bool matcapPerspective, float matcapVRParallaxStrength)
|
|
{
|
|
// Simple
|
|
//return mul((float3x3)LIL_MATRIX_V, normalWS).xy * 0.5 + 0.5;
|
|
float3 normalVD = lilBlendVRParallax(headDirection, viewDirection, matcapVRParallaxStrength);
|
|
normalVD = lilIsPerspective() && matcapPerspective ? normalVD : lilCameraDirection();
|
|
float3 bitangentVD = zRotCancel ? float3(0,1,0) : LIL_MATRIX_V._m10_m11_m12;
|
|
bitangentVD = lilOrthoNormalize(bitangentVD, normalVD);
|
|
float3 tangentVD = cross(normalVD, bitangentVD);
|
|
float3x3 tbnVD = float3x3(tangentVD, bitangentVD, normalVD);
|
|
float2 uvMat = mul(tbnVD, normalWS).xy;
|
|
uvMat = lerp(uvMat, uv1*2-1, matcapBlendUV1);
|
|
uvMat = uvMat * matcap_ST.xy + matcap_ST.zw;
|
|
uvMat = uvMat * 0.5 + 0.5;
|
|
return uvMat;
|
|
}
|
|
|
|
// Panorama
|
|
float2 lilGetPanoramaUV(float3 viewDirection)
|
|
{
|
|
return float2(lilAtan(viewDirection.x, viewDirection.z), lilAcos(viewDirection.y)) * LIL_INV_PI;
|
|
}
|
|
|
|
// Parallax
|
|
void lilParallax(inout float2 uvMain, inout float2 uv, lilBool useParallax, float2 parallaxOffset, TEXTURE2D(parallaxMap), float parallaxScale, float parallaxOffsetParam)
|
|
{
|
|
if(useParallax)
|
|
{
|
|
float height = (LIL_SAMPLE_2D_LOD(parallaxMap,sampler_linear_repeat,uvMain,0).r - parallaxOffsetParam) * parallaxScale;
|
|
uvMain += height * parallaxOffset;
|
|
uv += height * parallaxOffset;
|
|
}
|
|
}
|
|
|
|
void lilPOM(inout float2 uvMain, inout float2 uv, lilBool useParallax, float4 uv_st, float3 parallaxViewDirection, TEXTURE2D(parallaxMap), float parallaxScale, float parallaxOffsetParam)
|
|
{
|
|
#define LIL_POM_DETAIL 200
|
|
if(useParallax)
|
|
{
|
|
float height;
|
|
float height2;
|
|
float3 rayStep = -parallaxViewDirection;
|
|
float3 rayPos = float3(uvMain, 1.0) + (1.0-parallaxOffsetParam) * parallaxScale * parallaxViewDirection;
|
|
rayStep.xy *= uv_st.xy;
|
|
rayStep = rayStep / LIL_POM_DETAIL;
|
|
rayStep.z /= parallaxScale;
|
|
|
|
for(int i = 0; i < LIL_POM_DETAIL * 2 * parallaxScale; ++i)
|
|
{
|
|
height2 = height;
|
|
rayPos += rayStep;
|
|
height = LIL_SAMPLE_2D_LOD(parallaxMap,sampler_linear_repeat,rayPos.xy,0).r;
|
|
if(height >= rayPos.z) break;
|
|
}
|
|
|
|
float2 prevObjPoint = rayPos.xy - rayStep.xy;
|
|
float nextHeight = height - rayPos.z;
|
|
float prevHeight = height2 - rayPos.z + rayStep.z;
|
|
|
|
float weight = nextHeight / (nextHeight - prevHeight);
|
|
rayPos.xy = lerp(rayPos.xy, prevObjPoint, weight);
|
|
|
|
uv += rayPos.xy - uvMain;
|
|
uvMain = rayPos.xy;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Effect
|
|
float lilCalcBlink(float4 blink)
|
|
{
|
|
float outBlink = sin(LIL_TIME * blink.z + blink.w) * 0.5 + 0.5;
|
|
if(blink.y > 0.5) outBlink = round(outBlink);
|
|
return lerp(1.0, outBlink, blink.x);
|
|
}
|
|
|
|
void lilCalcDissolve(
|
|
inout float alpha,
|
|
inout float dissolveAlpha,
|
|
float2 uv,
|
|
float3 positionOS,
|
|
float4 dissolveParams,
|
|
float4 dissolvePos,
|
|
TEXTURE2D(dissolveMask),
|
|
float4 dissolveMask_ST,
|
|
bool dissolveMaskEnabled
|
|
LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
if(dissolveParams.r)
|
|
{
|
|
float dissolveMaskVal = 1.0;
|
|
if(dissolveParams.r == 1.0 && dissolveMaskEnabled)
|
|
{
|
|
dissolveMaskVal = LIL_SAMPLE_2D(dissolveMask, samp, lilCalcUV(uv, dissolveMask_ST)).r;
|
|
}
|
|
if(dissolveParams.r == 1.0)
|
|
{
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveMaskVal - dissolveParams.b) / dissolveParams.a);
|
|
dissolveMaskVal = dissolveMaskVal > dissolveParams.b ? 1.0 : 0.0;
|
|
}
|
|
if(dissolveParams.r == 2.0)
|
|
{
|
|
dissolveAlpha = dissolveParams.g == 1.0 ? lilRotateUV(uv, dissolvePos.w).x : distance(uv, dissolvePos.xy);
|
|
dissolveMaskVal *= dissolveAlpha > dissolveParams.b ? 1.0 : 0.0;
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveAlpha - dissolveParams.b) / dissolveParams.a);
|
|
}
|
|
if(dissolveParams.r == 3.0)
|
|
{
|
|
dissolveAlpha = dissolveParams.g == 1.0 ? dot(positionOS, normalize(dissolvePos.xyz)).x : distance(positionOS, dissolvePos.xyz);
|
|
dissolveMaskVal *= dissolveAlpha > dissolveParams.b ? 1.0 : 0.0;
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveAlpha - dissolveParams.b) / dissolveParams.a);
|
|
}
|
|
alpha *= dissolveMaskVal;
|
|
}
|
|
}
|
|
|
|
void lilCalcDissolveWithNoise(
|
|
inout float alpha,
|
|
inout float dissolveAlpha,
|
|
float2 uv,
|
|
float3 positionOS,
|
|
float4 dissolveParams,
|
|
float4 dissolvePos,
|
|
TEXTURE2D(dissolveMask),
|
|
float4 dissolveMask_ST,
|
|
bool dissolveMaskEnabled,
|
|
TEXTURE2D(dissolveNoiseMask),
|
|
float4 dissolveNoiseMask_ST,
|
|
float4 dissolveNoiseMask_ScrollRotate,
|
|
float dissolveNoiseStrength
|
|
LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
if(dissolveParams.r)
|
|
{
|
|
float dissolveMaskVal = 1.0;
|
|
float dissolveNoise = 0.0;
|
|
if(dissolveParams.r == 1.0 && dissolveMaskEnabled)
|
|
{
|
|
dissolveMaskVal = LIL_SAMPLE_2D(dissolveMask, samp, lilCalcUV(uv, dissolveMask_ST)).r;
|
|
}
|
|
dissolveNoise = LIL_SAMPLE_2D(dissolveNoiseMask, samp, lilCalcUV(uv, dissolveNoiseMask_ST, dissolveNoiseMask_ScrollRotate.xy)).r - 0.5;
|
|
dissolveNoise *= dissolveNoiseStrength;
|
|
if(dissolveParams.r == 1.0)
|
|
{
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveMaskVal + dissolveNoise - dissolveParams.b) / dissolveParams.a);
|
|
dissolveMaskVal = dissolveMaskVal + dissolveNoise > dissolveParams.b ? 1.0 : 0.0;
|
|
}
|
|
if(dissolveParams.r == 2.0)
|
|
{
|
|
dissolveAlpha = dissolveParams.g == 1.0 ? dot(uv, normalize(dissolvePos.xy)) + dissolveNoise : distance(uv, dissolvePos.xy) + dissolveNoise;
|
|
dissolveMaskVal *= dissolveAlpha > dissolveParams.b ? 1.0 : 0.0;
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveAlpha - dissolveParams.b) / dissolveParams.a);
|
|
}
|
|
if(dissolveParams.r == 3.0)
|
|
{
|
|
dissolveAlpha = dissolveParams.g == 1.0 ? dot(positionOS, normalize(dissolvePos.xyz)) + dissolveNoise : distance(positionOS, dissolvePos.xyz) + dissolveNoise;
|
|
dissolveMaskVal *= dissolveAlpha > dissolveParams.b ? 1.0 : 0.0;
|
|
dissolveAlpha = 1.0 - saturate(abs(dissolveAlpha - dissolveParams.b) / dissolveParams.a);
|
|
}
|
|
alpha *= dissolveMaskVal;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Sub Texture
|
|
float4 lilGetSubTex(
|
|
TEXTURE2D(tex),
|
|
float4 uv_ST,
|
|
float angle,
|
|
float2 uv,
|
|
float nv,
|
|
bool isDecal,
|
|
bool isLeftOnly,
|
|
bool isRightOnly,
|
|
bool shouldCopy,
|
|
bool shouldFlipMirror,
|
|
bool shouldFlipCopy,
|
|
bool isMSDF,
|
|
bool isRightHand,
|
|
float4 decalAnimation,
|
|
float4 decalSubParam
|
|
LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
#if defined(LIL_FEATURE_DECAL)
|
|
float2 uv2 = lilCalcDecalUV(uv, uv_ST, angle, isLeftOnly, isRightOnly, shouldCopy, shouldFlipMirror, shouldFlipCopy, isRightHand);
|
|
#if defined(LIL_FEATURE_ANIMATE_DECAL)
|
|
float2 uv2samp = lilCalcAtlasAnimation(uv2, decalAnimation, decalSubParam);
|
|
#else
|
|
float2 uv2samp = uv2;
|
|
#endif
|
|
float4 outCol = LIL_SAMPLE_2D(tex,samp,uv2samp);
|
|
if(isMSDF) outCol = float4(1.0, 1.0, 1.0, lilMSDF(outCol.rgb));
|
|
if(isDecal) outCol.a *= lilIsIn0to1(uv2, saturate(nv-0.05));
|
|
return outCol;
|
|
#else
|
|
float2 uv2 = lilCalcUV(uv, uv_ST, angle);
|
|
float4 outCol = LIL_SAMPLE_2D(tex,samp,uv2);
|
|
if(isMSDF) outCol = float4(1.0, 1.0, 1.0, lilMSDF(outCol.rgb));
|
|
return outCol;
|
|
#endif
|
|
}
|
|
|
|
float4 lilGetSubTexWithoutAnimation(
|
|
TEXTURE2D(tex),
|
|
float4 uv_ST,
|
|
float angle,
|
|
float2 uv,
|
|
float nv,
|
|
bool isDecal,
|
|
bool isLeftOnly,
|
|
bool isRightOnly,
|
|
bool shouldCopy,
|
|
bool shouldFlipMirror,
|
|
bool shouldFlipCopy,
|
|
bool isMSDF,
|
|
bool isRightHand
|
|
LIL_SAMP_IN_FUNC(samp))
|
|
{
|
|
#if defined(LIL_FEATURE_DECAL)
|
|
float2 uv2 = lilCalcDecalUV(uv, uv_ST, angle, isLeftOnly, isRightOnly, shouldCopy, shouldFlipMirror, shouldFlipCopy, isRightHand);
|
|
float4 outCol = LIL_SAMPLE_2D(tex,samp,uv2);
|
|
if(isMSDF) outCol = float4(1.0, 1.0, 1.0, lilMSDF(outCol.rgb));
|
|
if(isDecal) outCol.a *= lilIsIn0to1(uv2, saturate(nv-0.05));
|
|
return outCol;
|
|
#else
|
|
float2 uv2 = lilCalcUV(uv, uv_ST, angle);
|
|
float4 outCol = LIL_SAMPLE_2D(tex,samp,uv2);
|
|
if(isMSDF) outCol = float4(1.0, 1.0, 1.0, lilMSDF(outCol.rgb));
|
|
return outCol;
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Light Direction
|
|
float3 lilGetCustomLightDirection(float4 lightDirectionOverride)
|
|
{
|
|
float3 customDir = length(lightDirectionOverride.xyz) * normalize(mul((float3x3)LIL_MATRIX_M, lightDirectionOverride.xyz));
|
|
return lightDirectionOverride.w ? customDir : lightDirectionOverride.xyz;
|
|
}
|
|
|
|
float3 lilGetLightDirectionForSH9()
|
|
{
|
|
float3 mainDir = LIL_MAINLIGHT_DIRECTION * lilLuminance(LIL_MAINLIGHT_COLOR);
|
|
float3 sh9Dir = unity_SHAr.xyz * 0.333333 + unity_SHAg.xyz * 0.333333 + unity_SHAb.xyz * 0.333333;
|
|
float3 lightDirectionForSH9 = sh9Dir + mainDir;
|
|
return dot(lightDirectionForSH9,lightDirectionForSH9) < 0.000001 ? 0 : normalize(lightDirectionForSH9);
|
|
}
|
|
|
|
float3 lilGetLightDirection(float4 lightDirectionOverride)
|
|
{
|
|
float3 mainDir = LIL_MAINLIGHT_DIRECTION * lilLuminance(LIL_MAINLIGHT_COLOR);
|
|
float3 sh9Dir = unity_SHAr.xyz * 0.333333 + unity_SHAg.xyz * 0.333333 + unity_SHAb.xyz * 0.333333;
|
|
return normalize(mainDir + sh9Dir + lilGetCustomLightDirection(lightDirectionOverride));
|
|
}
|
|
|
|
float3 lilGetFixedLightDirection(float4 lightDirectionOverride, bool doNormalise)
|
|
{
|
|
float3 mainDir = LIL_MAINLIGHT_DIRECTION * lilLuminance(LIL_MAINLIGHT_COLOR);
|
|
float3 sh9Dir = unity_SHAr.xyz * 0.333333 + unity_SHAg.xyz * 0.333333 + unity_SHAb.xyz * 0.333333;
|
|
float3 L = float3(sh9Dir.x, abs(sh9Dir.y), sh9Dir.z) + mainDir + lilGetCustomLightDirection(lightDirectionOverride);
|
|
return doNormalise ? normalize(L) : L;
|
|
}
|
|
|
|
float3 lilGetFixedLightDirection(float4 lightDirectionOverride)
|
|
{
|
|
return lilGetFixedLightDirection(lightDirectionOverride, true);
|
|
}
|
|
|
|
float3 lilGetLightDirection()
|
|
{
|
|
return lilGetLightDirection(float4(0.001,0.002,0.001,0.0));
|
|
}
|
|
|
|
float3 lilGetLightDirection(float3 positionWS)
|
|
{
|
|
#if defined(POINT) || defined(SPOT) || defined(POINT_COOKIE)
|
|
return normalize(LIL_MAINLIGHT_DIRECTION - positionWS);
|
|
#else
|
|
return LIL_MAINLIGHT_DIRECTION;
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// SH Lighting
|
|
float3 lilShadeSH9(float4 normalWS)
|
|
{
|
|
float3 res;
|
|
res.r = dot(unity_SHAr,normalWS);
|
|
res.g = dot(unity_SHAg,normalWS);
|
|
res.b = dot(unity_SHAb,normalWS);
|
|
float4 vB = normalWS.xyzz * normalWS.yzzx;
|
|
res.r += dot(unity_SHBr,vB);
|
|
res.g += dot(unity_SHBg,vB);
|
|
res.b += dot(unity_SHBb,vB);
|
|
res += unity_SHC.rgb * (normalWS.x * normalWS.x - normalWS.y * normalWS.y);
|
|
#ifdef LIL_COLORSPACE_GAMMA
|
|
res = lilLinearToSRGB(res);
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
float3 lilShadeSH9(float3 normalWS)
|
|
{
|
|
return lilShadeSH9(float4(normalWS,1.0));
|
|
}
|
|
|
|
float3 lilShadeSH9LPPV(float4 normalWS, float3 positionWS)
|
|
{
|
|
float4 SHAr = unity_SHAr;
|
|
float4 SHAg = unity_SHAg;
|
|
float4 SHAb = unity_SHAb;
|
|
#if defined(LIL_USE_LPPV)
|
|
if(unity_ProbeVolumeParams.x == 1.0)
|
|
{
|
|
float3 position = (unity_ProbeVolumeParams.y == 1.0) ? lilOptMul(unity_ProbeVolumeWorldToObject, positionWS).xyz : positionWS;
|
|
float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz;
|
|
texCoord.x = texCoord.x * 0.25;
|
|
float texCoordX = clamp(texCoord.x, 0.5 * unity_ProbeVolumeParams.z, 0.25 - 0.5 * unity_ProbeVolumeParams.z);
|
|
texCoord.x = texCoordX;
|
|
SHAr = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
texCoord.x = texCoordX + 0.25;
|
|
SHAg = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
texCoord.x = texCoordX + 0.5;
|
|
SHAb = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
}
|
|
#endif
|
|
float3 res;
|
|
res.r = dot(SHAr,normalWS);
|
|
res.g = dot(SHAg,normalWS);
|
|
res.b = dot(SHAb,normalWS);
|
|
float4 vB = normalWS.xyzz * normalWS.yzzx;
|
|
res.r += dot(unity_SHBr,vB);
|
|
res.g += dot(unity_SHBg,vB);
|
|
res.b += dot(unity_SHBb,vB);
|
|
res += unity_SHC.rgb * (normalWS.x * normalWS.x - normalWS.y * normalWS.y);
|
|
#ifdef LIL_COLORSPACE_GAMMA
|
|
res = lilLinearToSRGB(res);
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
float3 lilShadeSH9LPPV(float3 normalWS, float3 positionWS)
|
|
{
|
|
return lilShadeSH9LPPV(float4(normalWS,1.0), positionWS);
|
|
}
|
|
|
|
float3 lilGetSHToon()
|
|
{
|
|
return lilShadeSH9(lilGetLightDirectionForSH9() * 0.666666);
|
|
}
|
|
|
|
float3 lilGetSHToon(float3 positionWS)
|
|
{
|
|
return lilShadeSH9LPPV(lilGetLightDirectionForSH9() * 0.666666, positionWS);
|
|
}
|
|
|
|
float3 lilGetSHToonMin()
|
|
{
|
|
return lilShadeSH9(-lilGetLightDirectionForSH9() * 0.666666);
|
|
}
|
|
|
|
float3 lilGetSHToonMin(float3 positionWS)
|
|
{
|
|
return lilShadeSH9LPPV(-lilGetLightDirectionForSH9() * 0.666666, positionWS);
|
|
}
|
|
|
|
void lilGetToonSHDouble(float3 lightDirection, out float3 shMax, out float3 shMin)
|
|
{
|
|
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;
|
|
#ifdef LIL_COLORSPACE_GAMMA
|
|
shMax = lilLinearToSRGB(shMax);
|
|
shMin = lilLinearToSRGB(shMin);
|
|
#endif
|
|
}
|
|
|
|
void lilGetToonSHDoubleLPPV(float3 lightDirection, float3 positionWS, out float3 shMax, out float3 shMin)
|
|
{
|
|
float4 SHAr = unity_SHAr;
|
|
float4 SHAg = unity_SHAg;
|
|
float4 SHAb = unity_SHAb;
|
|
#if defined(LIL_USE_LPPV)
|
|
if(unity_ProbeVolumeParams.x == 1.0)
|
|
{
|
|
float3 position = (unity_ProbeVolumeParams.y == 1.0) ? lilOptMul(unity_ProbeVolumeWorldToObject, positionWS).xyz : positionWS;
|
|
float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz;
|
|
texCoord.x = texCoord.x * 0.25;
|
|
float texCoordX = clamp(texCoord.x, 0.5 * unity_ProbeVolumeParams.z, 0.25 - 0.5 * unity_ProbeVolumeParams.z);
|
|
texCoord.x = texCoordX;
|
|
SHAr = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
texCoord.x = texCoordX + 0.25;
|
|
SHAg = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
texCoord.x = texCoordX + 0.5;
|
|
SHAb = LIL_SAMPLE_3D(unity_ProbeVolumeSH, samplerunity_ProbeVolumeSH, texCoord);
|
|
}
|
|
#endif
|
|
float3 N = lightDirection * 0.666666;
|
|
float4 vB = N.xyzz * N.yzzx;
|
|
// L0 L2
|
|
float3 res = float3(SHAr.w,SHAg.w,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(SHAr.rgb, N);
|
|
l1.g = dot(SHAg.rgb, N);
|
|
l1.b = dot(SHAb.rgb, N);
|
|
shMax = res + l1;
|
|
shMin = res - l1;
|
|
#ifdef LIL_COLORSPACE_GAMMA
|
|
shMax = lilLinearToSRGB(shMax);
|
|
shMin = lilLinearToSRGB(shMin);
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Lighting
|
|
float3 lilGetLightColor()
|
|
{
|
|
return LIL_MAINLIGHT_COLOR + lilGetSHToon();
|
|
}
|
|
|
|
float3 lilGetLightColor(float3 positionWS)
|
|
{
|
|
return LIL_MAINLIGHT_COLOR + lilGetSHToon(positionWS);
|
|
}
|
|
|
|
float3 lilGetIndirLightColor()
|
|
{
|
|
return saturate(lilGetSHToonMin());
|
|
}
|
|
|
|
float3 lilGetIndirLightColor(float3 positionWS)
|
|
{
|
|
return saturate(lilGetSHToonMin(positionWS));
|
|
}
|
|
|
|
void lilGetLightColorDouble(out float3 lightColor, out float3 indLightColor)
|
|
{
|
|
float3 shMax, shMin;
|
|
lilGetToonSHDouble(lilGetLightDirectionForSH9(), shMax, shMin);
|
|
lightColor = LIL_MAINLIGHT_COLOR + shMax;
|
|
indLightColor = saturate(shMin);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Geometric Specular Antialiasing
|
|
void GSAA(inout float roughness, float3 N, float strength)
|
|
{
|
|
float3 dx = abs(ddx(N));
|
|
float3 dy = abs(ddy(N));
|
|
float dxy = max(dot(dx,dx), dot(dy,dy));
|
|
float roughnessGSAA = dxy / (dxy * 5 + 0.002) * strength;
|
|
roughness = max(roughness, roughnessGSAA);
|
|
}
|
|
|
|
void GSAAForSmoothness(inout float smoothness, float3 N, float strength)
|
|
{
|
|
float roughness = 0;
|
|
GSAA(roughness, N, strength);
|
|
smoothness = min(smoothness, saturate(1-roughness));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Specular
|
|
float3 lilFresnelTerm(float3 F0, float cosA)
|
|
{
|
|
float a = 1.0-cosA;
|
|
return F0 + (1-F0) * a * a * a * a * a;
|
|
}
|
|
|
|
float3 lilFresnelLerp(float3 F0, float3 F90, float cosA)
|
|
{
|
|
float a = 1.0-cosA;
|
|
return lerp(F0, F90, a * a * a * a * a);
|
|
}
|
|
|
|
float3 lilGetAnisotropyNormalWS(float3 normalWS, float3 anisoTangentWS, float3 anisoBitangentWS, float3 viewDirection, float anisotropy)
|
|
{
|
|
float3 anisoDirectionWS = anisotropy > 0.0 ? anisoBitangentWS : anisoTangentWS;
|
|
anisoDirectionWS = lilOrthoNormalize(viewDirection, anisoDirectionWS);
|
|
return normalize(lerp(normalWS, anisoDirectionWS, abs(anisotropy)));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Reflection
|
|
float3 lilCustomReflection(TEXTURECUBE(tex), float4 hdr, float3 viewDirection, float3 normalDirection, float perceptualRoughness)
|
|
{
|
|
float mip = perceptualRoughness * (10.2 - 4.2 * perceptualRoughness);
|
|
float3 refl = reflect(-viewDirection, normalDirection);
|
|
return lilDecodeHDR(LIL_SAMPLE_CUBE_LOD(tex, sampler_linear_repeat, refl, mip), hdr);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Glitter
|
|
float4 lilVoronoi(float2 pos, out float2 nearoffset, float scaleRandomize)
|
|
{
|
|
#if defined(SHADER_API_D3D9) || defined(SHADER_API_D3D11_9X)
|
|
#define M1 46203.4357
|
|
#define M2 21091.5327
|
|
#define M3 35771.1966
|
|
float2 q = trunc(pos);
|
|
float4 q2 = float4(q.x, q.y, q.x+1, q.y+1);
|
|
float3 noise0 = frac(sin(dot(q2.xy,float2(12.9898,78.233))) * float3(M1, M2, M3));
|
|
float3 noise1 = frac(sin(dot(q2.zy,float2(12.9898,78.233))) * float3(M1, M2, M3));
|
|
float3 noise2 = frac(sin(dot(q2.xw,float2(12.9898,78.233))) * float3(M1, M2, M3));
|
|
float3 noise3 = frac(sin(dot(q2.zw,float2(12.9898,78.233))) * float3(M1, M2, M3));
|
|
#undef M1
|
|
#undef M2
|
|
#undef M3
|
|
#else
|
|
float3 noise0, noise1, noise2, noise3;
|
|
lilHashRGB4(pos, noise0, noise1, noise2, noise3);
|
|
#endif
|
|
|
|
// Get the nearest position
|
|
float4 fracpos = frac(pos).xyxy + float4(0.5,0.5,-0.5,-0.5);
|
|
float4 dist4 = float4(lilNsqDistance(fracpos.xy,noise0.xy), lilNsqDistance(fracpos.zy,noise1.xy), lilNsqDistance(fracpos.xw,noise2.xy), lilNsqDistance(fracpos.zw,noise3.xy));
|
|
dist4 = lerp(dist4, dist4 / max(float4(noise0.z, noise1.z, noise2.z, noise3.z), 0.001), scaleRandomize);
|
|
|
|
float3 nearoffset0 = dist4.x < dist4.y ? float3(0,0,dist4.x) : float3(1,0,dist4.y);
|
|
float3 nearoffset1 = dist4.z < dist4.w ? float3(0,1,dist4.z) : float3(1,1,dist4.w);
|
|
nearoffset = nearoffset0.z < nearoffset1.z ? nearoffset0.xy : nearoffset1.xy;
|
|
|
|
float4 near0 = dist4.x < dist4.y ? float4(noise0,dist4.x) : float4(noise1,dist4.y);
|
|
float4 near1 = dist4.z < dist4.w ? float4(noise2,dist4.z) : float4(noise3,dist4.w);
|
|
return near0.w < near1.w ? near0 : near1;
|
|
}
|
|
|
|
float3 lilCalcGlitter(float2 uv, float3 normalDirection, float3 viewDirection, float3 cameraDirection, float3 lightDirection, float4 glitterParams1, float4 glitterParams2, float glitterPostContrast, float glitterSensitivity, float glitterScaleRandomize, uint glitterAngleRandomize, bool glitterApplyShape, TEXTURE2D(glitterShapeTex), float4 glitterShapeTex_ST, float4 glitterAtras)
|
|
{
|
|
// glitterParams1
|
|
// x: Scale, y: Scale, z: Size, w: Contrast
|
|
// glitterParams2
|
|
// x: Speed, y: Angle, z: Light Direction, w:
|
|
|
|
#define GLITTER_DEBUG_MODE 0
|
|
#define GLITTER_MIPMAP 1
|
|
#define GLITTER_ANTIALIAS 1
|
|
|
|
#if GLITTER_MIPMAP == 1
|
|
float2 pos = uv * glitterParams1.xy;
|
|
float2 dd = fwidth(pos);
|
|
float factor = frac(sin(dot(floor(pos/floor(dd + 3.0)),float2(12.9898,78.233))) * 46203.4357) + 0.5;
|
|
float2 factor2 = floor(dd + factor * 0.5);
|
|
pos = pos/max(1.0,factor2) + glitterParams1.xy * factor2;
|
|
#else
|
|
float2 pos = uv * glitterParams1.xy + glitterParams1.xy;
|
|
#endif
|
|
float2 nearoffset;
|
|
float4 near = lilVoronoi(pos, nearoffset, glitterScaleRandomize);
|
|
|
|
|
|
#if GLITTER_DEBUG_MODE == 1
|
|
// Voronoi
|
|
return near.x;
|
|
#else
|
|
// Glitter
|
|
float3 glitterNormal = abs(frac(near.xyz*14.274 + _Time.x * glitterParams2.x) * 2.0 - 1.0);
|
|
glitterNormal = normalize(glitterNormal * 2.0 - 1.0);
|
|
float glitter = dot(glitterNormal, cameraDirection);
|
|
glitter = abs(frac(glitter * glitterSensitivity + glitterSensitivity) - 0.5) * 4.0 - 1.0;
|
|
glitter = saturate(1.0 - (glitter * glitterParams1.w + glitterParams1.w));
|
|
glitter = pow(glitter, glitterPostContrast);
|
|
// Circle
|
|
#if GLITTER_ANTIALIAS == 1
|
|
glitter *= saturate((glitterParams1.z-near.w) / fwidth(near.w));
|
|
#else
|
|
glitter = near.w < glitterParams1.z ? glitter : 0.0;
|
|
#endif
|
|
// Angle
|
|
float3 halfDirection = normalize(viewDirection + lightDirection * glitterParams2.z);
|
|
float nh = saturate(dot(normalDirection, halfDirection));
|
|
glitter = saturate(glitter * saturate(nh * glitterParams2.y + 1.0 - glitterParams2.y));
|
|
// Random Color
|
|
float3 glitterColor = glitter - glitter * frac(near.xyz*278.436) * glitterParams2.w;
|
|
// Shape
|
|
#if defined(LIL_FEATURE_GlitterShapeTex)
|
|
if(glitterApplyShape)
|
|
{
|
|
float2 maskUV = pos - floor(pos) - nearoffset + 0.5 - near.xy;
|
|
maskUV = maskUV / glitterParams1.z * glitterShapeTex_ST.xy + glitterShapeTex_ST.zw;
|
|
if(glitterAngleRandomize)
|
|
{
|
|
float si,co;
|
|
sincos(near.z * 785.238, si, co);
|
|
maskUV = float2(
|
|
maskUV.x * co - maskUV.y * si,
|
|
maskUV.x * si + maskUV.y * co
|
|
);
|
|
}
|
|
float randomScale = lerp(1.0, 1.0 / sqrt(max(near.z, 0.001)), glitterScaleRandomize);
|
|
maskUV = maskUV * randomScale + 0.5;
|
|
bool clamp = maskUV.x == saturate(maskUV.x) && maskUV.y == saturate(maskUV.y);
|
|
maskUV = (maskUV + floor(near.xy * glitterAtras.xy)) / glitterAtras.xy;
|
|
float2 mipfactor = 0.125 / glitterParams1.z * glitterAtras.xy * glitterShapeTex_ST.xy * randomScale;
|
|
float4 shapeTex = LIL_SAMPLE_2D_GRAD(glitterShapeTex, sampler_linear_clamp, maskUV, abs(ddx(pos)) * mipfactor.x, abs(ddy(pos)) * mipfactor.y);
|
|
shapeTex.a = clamp ? shapeTex.a : 0;
|
|
glitterColor *= shapeTex.rgb * shapeTex.a;
|
|
}
|
|
#endif
|
|
return glitterColor;
|
|
#endif
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
// Tessellation
|
|
float lilCalcEdgeTessFactor(float3 wpos0, float3 wpos1, float edgeLen)
|
|
{
|
|
float dist = distance(0.5 * (wpos0+wpos1), _WorldSpaceCameraPos.xyz);
|
|
return max(distance(wpos0, wpos1) * LIL_SCREENPARAMS.y / (edgeLen * dist), 1.0);
|
|
}
|
|
|
|
#endif |