#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