void calcNormal(inout XSLighting i) { if(_NormalMapMode == 0) { half3 nMap = UnpackScaleNormal(i.normalMap, _BumpScale); half3 detNMap = UnpackScaleNormal(i.detailNormal, _DetailNormalMapScale); half3 blendedNormal = lerp(nMap, BlendNormals(nMap, detNMap), i.detailMask.r); half3 tspace0 = half3(i.tangent.x, i.bitangent.x, i.normal.x); half3 tspace1 = half3(i.tangent.y, i.bitangent.y, i.normal.y); half3 tspace2 = half3(i.tangent.z, i.bitangent.z, i.normal.z); half3 calcedNormal; calcedNormal.x = dot(tspace0, blendedNormal); calcedNormal.y = dot(tspace1, blendedNormal); calcedNormal.z = dot(tspace2, blendedNormal); calcedNormal = normalize(calcedNormal); half3 bumpedTangent = cross(i.bitangent, calcedNormal); half3 bumpedBitangent = cross(calcedNormal, bumpedTangent); i.normal = calcedNormal; i.tangent = bumpedTangent; i.bitangent = bumpedBitangent; } else { float3 vcol = i.color.rgb * 2 - 1; half3 tspace0 = half3(i.tangent.x, i.bitangent.x, i.normal.x); half3 tspace1 = half3(i.tangent.y, i.bitangent.y, i.normal.y); half3 tspace2 = half3(i.tangent.z, i.bitangent.z, i.normal.z); half3 calcedNormal; calcedNormal.x = dot(tspace0, vcol); calcedNormal.y = dot(tspace1, vcol); calcedNormal.z = dot(tspace2, vcol); //calcedNormal = calcedNormal; i.normal = normalize(calcedNormal); } } void InitializeTextureUVs( #if defined(Geometry) in g2f i, #else in VertexOutput i, #endif inout TextureUV t) { #if defined(PatreonEyeTracking) float2 eyeUvOffset = eyeOffsets(i.uv, i.objPos, i.worldPos, i.ntb[0]); i.uv = eyeUvOffset; i.uv1 = eyeUvOffset; #endif half2 uvSetAlbedo = (_UVSetAlbedo == 0) ? i.uv : i.uv1; t.albedoUV = TRANSFORM_TEX(uvSetAlbedo, _MainTex); half2 uvSetClipMap = (_UVSetClipMap == 0) ? i.uv : i.uv1; t.clipMapUV = TRANSFORM_TEX(uvSetClipMap, _ClipMap); half2 uvSetDissolveMap = (_UVSetDissolve == 0) ? i.uv : i.uv1; t.dissolveUV = TRANSFORM_TEX(uvSetDissolveMap, _DissolveTexture); #if !defined(UNITY_PASS_SHADOWCASTER) half2 uvSetNormalMap = (_UVSetNormal == 0) ? i.uv : i.uv1; t.normalMapUV = TRANSFORM_TEX(uvSetNormalMap, _BumpMap); half2 uvSetEmissionMap = (_UVSetEmission == 0) ? i.uv : i.uv1; t.emissionMapUV = TRANSFORM_TEX(uvSetEmissionMap, _EmissionMap); half2 uvSetMetallicGlossMap = (_UVSetMetallic == 0) ? i.uv : i.uv1; t.metallicGlossMapUV = TRANSFORM_TEX(uvSetMetallicGlossMap, _MetallicGlossMap); half2 uvSetOcclusion = (_UVSetOcclusion == 0) ? i.uv : i.uv1; t.occlusionUV = TRANSFORM_TEX(uvSetOcclusion, _OcclusionMap); half2 uvSetDetailNormal = (_UVSetDetNormal == 0) ? i.uv : i.uv1; t.detailNormalUV = TRANSFORM_TEX(uvSetDetailNormal, _DetailNormalMap); half2 uvSetDetailMask = (_UVSetDetMask == 0) ? i.uv : i.uv1; t.detailMaskUV = TRANSFORM_TEX(uvSetDetailMask, _DetailMask); half2 uvSetSpecularMap = (_UVSetSpecular == 0) ? i.uv : i.uv1; t.specularMapUV = TRANSFORM_TEX(uvSetSpecularMap, _SpecularMap); half2 uvSetThickness = (_UVSetThickness == 0) ? i.uv : i.uv1; t.thicknessMapUV = TRANSFORM_TEX(uvSetThickness, _ThicknessMap); half2 uvSetReflectivityMask = (_UVSetReflectivity == 0) ? i.uv : i.uv1; t.reflectivityMaskUV = TRANSFORM_TEX(uvSetReflectivityMask, _ReflectivityMask); #endif } float Remap_Float(float In, float2 InMinMax, float2 OutMinMax) { return OutMinMax.x + (In - InMinMax.x) * (OutMinMax.y - OutMinMax.x) / (InMinMax.y - InMinMax.x); } half3 rgb2hsv(half3 c) { half4 K = half4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); half4 p = lerp(half4(c.bg, K.wz), half4(c.gb, K.xy), step(c.b, c.g)); half4 q = lerp(half4(p.xyw, c.r), half4(c.r, p.yzx), step(p.x, c.r)); float d = q.x - min(q.w, q.y); float e = 1.0e-10; return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } half3 hsv2rgb(half3 c) { half4 K = half4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); half3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www); return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } void InitializeTextureUVsMerged( #if defined(Geometry) in g2f i, #else in VertexOutput i, #endif inout TextureUV t) { half2 uvSetAlbedo = (_UVSetAlbedo == 0) ? i.uv : i.uv1; t.albedoUV = TRANSFORM_TEX(uvSetAlbedo, _MainTex); t.normalMapUV = t.albedoUV; t.emissionMapUV = t.albedoUV; t.metallicGlossMapUV = t.albedoUV; t.occlusionUV = t.albedoUV; t.detailNormalUV = t.albedoUV; t.detailMaskUV = t.albedoUV; t.specularMapUV = t.albedoUV; t.thicknessMapUV = t.albedoUV; t.reflectivityMaskUV = t.albedoUV; t.clipMapUV = t.albedoUV; //Dissolve map makes sense to be on a sep. UV always. half2 uvSetDissolveMap = (_UVSetDissolve == 0) ? i.uv : i.uv1; t.dissolveUV = TRANSFORM_TEX(uvSetDissolveMap, _DissolveTexture); } bool IsInMirror() { return unity_CameraProjection[2][0] != 0.f || unity_CameraProjection[2][1] != 0.f; } inline half Dither8x8Bayer( int x, int y ) { const half dither[ 64 ] = { 1, 49, 13, 61, 4, 52, 16, 64, 33, 17, 45, 29, 36, 20, 48, 32, 9, 57, 5, 53, 12, 60, 8, 56, 41, 25, 37, 21, 44, 28, 40, 24, 3, 51, 15, 63, 2, 50, 14, 62, 35, 19, 47, 31, 34, 18, 46, 30, 11, 59, 7, 55, 10, 58, 6, 54, 43, 27, 39, 23, 42, 26, 38, 22}; int r = y * 8 + x; return dither[r] / 64; } half calcDither(half2 screenPos) { half dither = Dither8x8Bayer(fmod(screenPos.x, 8), fmod(screenPos.y, 8)); return dither; } half2 calcScreenUVs(half4 screenPos) { half2 uv = screenPos / (screenPos.w + 0.0000000001); //0.0x1 Stops division by 0 warning in console. #if UNITY_SINGLE_PASS_STEREO uv.xy *= half2(_ScreenParams.x * 2, _ScreenParams.y); #else uv.xy *= _ScreenParams.xy; #endif return uv; } half3 calcViewDir(half3 worldPos) { half3 viewDir = _WorldSpaceCameraPos - worldPos; return normalize(viewDir); } half3 calcStereoViewDir(half3 worldPos) { #if UNITY_SINGLE_PASS_STEREO half3 cameraPos = half3((unity_StereoWorldSpaceCameraPos[0]+ unity_StereoWorldSpaceCameraPos[1])*.5); #else half3 cameraPos = _WorldSpaceCameraPos; #endif half3 viewDir = cameraPos - worldPos; return normalize(viewDir); } half2 matcapSample(half3 worldUp, half3 viewDirection, half3 normalDirection) { half3 worldViewUp = normalize(worldUp - viewDirection * dot(viewDirection, worldUp)); half3 worldViewRight = normalize(cross(viewDirection, worldViewUp)); half2 matcapUV = half2(dot(worldViewRight, normalDirection), dot(worldViewUp, normalDirection)) * 0.5 + 0.5; return matcapUV; } //Reflection direction, worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax half3 getReflectionUV(half3 direction, half3 position, half4 cubemapPosition, half3 boxMin, half3 boxMax) { #if UNITY_SPECCUBE_BOX_PROJECTION if (cubemapPosition.w > 0) { half3 factors = ((direction > 0 ? boxMax : boxMin) - position) / direction; half scalar = min(min(factors.x, factors.y), factors.z); direction = direction * scalar + (position - cubemapPosition); } #endif return direction; } half3 getEnvMap(XSLighting i, DotProducts d, float blur, half3 reflDir, half3 indirectLight, half3 wnormal) {//This function handls Unity style reflections, Matcaps, and a baked in fallback cubemap. half3 envMap = half3(0,0,0); #if defined(UNITY_PASS_FORWARDBASE) //Indirect PBR specular should only happen in the forward base pass. Otherwise each extra light adds another indirect sample, which could mean you're getting too much light. half3 reflectionUV1 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube0_ProbePosition, unity_SpecCube0_BoxMin, unity_SpecCube0_BoxMax); half4 probe0 = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflectionUV1, blur); half3 probe0sample = DecodeHDR(probe0, unity_SpecCube0_HDR); half3 indirectSpecular; half interpolator = unity_SpecCube0_BoxMin.w; UNITY_BRANCH if (interpolator < 0.99999) { half3 reflectionUV2 = getReflectionUV(reflDir, i.worldPos, unity_SpecCube1_ProbePosition, unity_SpecCube1_BoxMin, unity_SpecCube1_BoxMax); half4 probe1 = UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(unity_SpecCube1, unity_SpecCube0, reflectionUV2, blur); half3 probe1sample = DecodeHDR(probe1, unity_SpecCube1_HDR); indirectSpecular = lerp(probe1sample, probe0sample, interpolator); } else { indirectSpecular = probe0sample; } envMap = indirectSpecular; #endif return envMap; } float AlphaAdjust(float alphaToAdj, float3 vColor) { _ClipAgainstVertexColorGreaterZeroFive = saturate(_ClipAgainstVertexColorGreaterZeroFive); //So the lerp doesn't go crazy _ClipAgainstVertexColorLessZeroFive = saturate(_ClipAgainstVertexColorLessZeroFive); float modR = vColor.r < 0.5 ? _ClipAgainstVertexColorLessZeroFive.r : _ClipAgainstVertexColorGreaterZeroFive.r; float modG = vColor.g < 0.5 ? _ClipAgainstVertexColorLessZeroFive.g : _ClipAgainstVertexColorGreaterZeroFive.g; float modB = vColor.b < 0.5 ? _ClipAgainstVertexColorLessZeroFive.b : _ClipAgainstVertexColorGreaterZeroFive.b; alphaToAdj *= lerp(0, 1, lerp(1, modR, step(0.01, vColor.r))); alphaToAdj *= lerp(0, 1, lerp(1, modG, step(0.01, vColor.g))); alphaToAdj *= lerp(0, 1, lerp(1, modB, step(0.01, vColor.b))); return alphaToAdj; } void calcDissolve(inout XSLighting i, inout float4 col) { #ifdef _ALPHATEST_ON half dissolveAmt = Remap_Float(i.dissolveMask.x, float2(0,1), float2(0.1, 0.9)); half dissolveProgress = saturate(_DissolveProgress + lerp(0, 1-AlphaAdjust(1, i.clipMap.rgb), _UseClipsForDissolve)); half dissolve = 0; if (_DissolveCoordinates == 0) { dissolve = dissolveAmt - dissolveProgress; clip(dissolve); } if(_DissolveCoordinates == 1) { half distToCenter = 1-length(i.objPos); dissolve = ((distToCenter + dissolveAmt) * 0.5) - dissolveProgress; clip(dissolve); } if(_DissolveCoordinates == 2) { half distToCenter = (1-i.objPos.y) * 0.5 + 0.5; dissolve = ((distToCenter + dissolveAmt) * 0.5) - dissolveProgress; clip(dissolve); } #if !defined(UNITY_PASS_SHADOWCASTER) float4 dissCol = _DissolveColor; dissCol.rgb = rgb2hsv(dissCol.rgb); dissCol.x += fmod(_Hue, 360); dissCol.y = saturate(dissCol.y * _Saturation); dissCol.z *= _Value; dissCol.rgb = hsv2rgb(dissCol.rgb); half dissolveEdge = smoothstep(dissolve, dissolve - (_DissolveStrength * 0.01), dissolve * dissolveAmt); col.rgb += (1-dissolveEdge) * dissCol.rgb; #endif #endif } void calcAlpha(inout XSLighting i) { i.alpha = 1; #ifdef _ALPHABLEND_ON i.alpha = i.albedo.a; #ifdef UNITY_PASS_SHADOWCASTER half dither = calcDither(i.screenUV.xy); clip(i.alpha - dither); #endif #endif #ifdef _ALPHATEST_ON float modifiedAlpha = lerp(AlphaAdjust(i.albedo.a, i.clipMap.rgb), i.albedo.a, _UseClipsForDissolve); if(_BlendMode >= 3) { half dither = calcDither(i.screenUV.xy); i.alpha = modifiedAlpha - (dither * (1-i.albedo.a) * 0.15); } if(_BlendMode == 2) { half dither = calcDither(i.screenUV.xy); float fadeDist = abs(_FadeDitherDistance); float d = distance(_WorldSpaceCameraPos, i.worldPos); d = smoothstep(fadeDist, fadeDist + 0.05, d); d = lerp(d, 1-d, saturate(step(0, _FadeDitherDistance))); dither += lerp(0, d, saturate(_FadeDither)); clip(modifiedAlpha - dither); } if(_BlendMode == 1) { clip(modifiedAlpha - _Cutoff); } #endif } // //Halftone functions, finish implementing later.. Not correct right now. float2 SphereUV( float3 coords /*viewDir?*/) { float3 nc = normalize(coords); float lat = acos(nc.y); float lon = atan2(nc.z, nc.x); float2 coord = 1.0 - (float2(lon, lat) * float2(1.0/UNITY_PI, 1.0/UNITY_PI)); return (coord + float4(0, 1-unity_StereoEyeIndex,1,1.0).xy) * float4(0, 1-unity_StereoEyeIndex,1,1.0).zw; } half2 rotateUV(half2 uv, half rotation) { half mid = 0.5; return half2( cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid, cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid ); } half DotHalftone(XSLighting i, half scalar) //Scalar can be anything from attenuation to a dot product { bool inMirror = IsInMirror(); half2 uv = SphereUV(calcViewDir(i.worldPos)); uv.xy *= _HalftoneDotAmount; half2 nearest = 2 * frac(100 * uv) - 1; half dist = length(nearest); half dotSize = 100 * _HalftoneDotSize * scalar; half dotMask = step(dotSize, dist); return lerp(1, 1-dotMask, smoothstep(0, 0.4, 1/distance(i.worldPos, _WorldSpaceCameraPos)));; } half LineHalftone(XSLighting i, half scalar) { // #if defined(DIRECTIONAL) // scalar = saturate(scalar + ((1-i.attenuation) * 0.2)); // #endif bool inMirror = IsInMirror(); half2 uv = SphereUV(calcViewDir(i.worldPos)); uv = rotateUV(uv, -0.785398); uv.x = sin(uv.x * _HalftoneLineAmount * scalar); half2 steppedUV = smoothstep(0,0.2,uv.x); half lineMask = lerp(1, steppedUV, smoothstep(0, 0.4, 1/distance(i.worldPos, _WorldSpaceCameraPos))); return saturate(lineMask); } //