354 lines
14 KiB
HLSL
354 lines
14 KiB
HLSL
#ifndef CHARACTERCOMMONUTIL_BASE
|
|
#define CHARACTERCOMMONUTIL_BASE
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
|
|
inline half3 BlendMode_Screen( half3 s, half3 d)
|
|
{
|
|
return s + d - s*d;
|
|
}
|
|
inline half3 RotationY(half3 pointP, half angle)
|
|
{
|
|
half radY = radians(angle);
|
|
half sinY = sin(radY);
|
|
half cosY = cos(radY);
|
|
return half3(pointP.x * cosY - pointP.z * sinY,
|
|
pointP.y, pointP.x * sinY + pointP.z * cosY);
|
|
}
|
|
inline half3 RgbToHsv_SGame(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));
|
|
half d = q.x - min(q.w, q.y);
|
|
half e = 1.0e-4;
|
|
return half3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
|
|
}
|
|
inline half3 HsvToRgb_SGame(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, saturate(p - K.xxx), c.y);
|
|
}
|
|
struct UnityLight
|
|
{
|
|
half3 color;
|
|
half3 dir;
|
|
half ndotl; // Deprecated: Ndotl is now calculated on the fly and is no longer stored. Do not used it.
|
|
};
|
|
struct UnityIndirect
|
|
{
|
|
half3 diffuse;
|
|
half3 specular;
|
|
};
|
|
struct UnityGI
|
|
{
|
|
UnityLight light;
|
|
UnityIndirect indirect;
|
|
};
|
|
struct UnityGIInput
|
|
{
|
|
UnityLight light; // pixel light, sent from the engine
|
|
float3 worldPos;
|
|
half3 worldViewDir;
|
|
half atten;
|
|
half3 ambient;
|
|
float4 lightmapUV; // .xy = static lightmap UV, .zw = dynamic lightmap UV
|
|
|
|
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION) || defined(UNITY_ENABLE_REFLECTION_BUFFERS)
|
|
float4 boxMin[2];
|
|
#endif
|
|
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
|
|
float4 boxMax[2];
|
|
float4 probePosition[2];
|
|
#endif
|
|
// HDR cubemap properties, use to decompress HDR texture
|
|
float4 probeHDR[2];
|
|
};
|
|
struct Unity_GlossyEnvironmentData
|
|
{
|
|
half roughness; // CAUTION: This is perceptualRoughness but because of compatibility this name can't be change :(
|
|
half3 reflUVW;
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------
|
|
half3 NormalizePerVertexNormal (float3 n) // takes float to avoid overflow
|
|
{
|
|
#if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
|
|
return normalize(n);
|
|
#else
|
|
return n; // will normalize per-pixel instead
|
|
#endif
|
|
}
|
|
half3 NormalizePerPixelNormal (half3 n)
|
|
{
|
|
#if (SHADER_TARGET < 30) || UNITY_STANDARD_SIMPLE
|
|
return n;
|
|
#else
|
|
return normalize(n);
|
|
#endif
|
|
}
|
|
//-------------------------------------------------------------------------------------
|
|
UnityLight MainLight ()
|
|
{
|
|
UnityLight l;
|
|
l.color = GetMainLight().color.rgb;
|
|
half3 hsvLightCol = RgbToHsv_SGame(GetMainLight().color.rgb);
|
|
hsvLightCol.b = clamp(hsvLightCol.b, 0.9, 1.1);
|
|
l.color = HsvToRgb_SGame(hsvLightCol);
|
|
l.dir = GetMainLight().direction;
|
|
return l;
|
|
}
|
|
UnityLight AdditiveLight (half3 lightDir, half atten)
|
|
{
|
|
UnityLight l;
|
|
l.color = GetMainLight().color.rgb;
|
|
l.dir = lightDir;
|
|
#ifndef USING_DIRECTIONAL_LIGHT
|
|
l.dir = NormalizePerPixelNormal(l.dir);
|
|
#endif
|
|
l.color *= atten;
|
|
return l;
|
|
}
|
|
UnityLight DummyLight ()
|
|
{
|
|
UnityLight l;
|
|
l.color = 0;
|
|
l.dir = half3 (0,1,0);
|
|
return l;
|
|
}
|
|
UnityIndirect ZeroIndirect ()
|
|
{
|
|
UnityIndirect ind;
|
|
ind.diffuse = 0;
|
|
ind.specular = 0;
|
|
return ind;
|
|
}
|
|
Unity_GlossyEnvironmentData UnityGlossyEnvironmentSetup(half Smoothness, half3 worldViewDir, half3 Normal, half3 fresnel0)
|
|
{
|
|
Unity_GlossyEnvironmentData g;
|
|
g.roughness /* perceptualRoughness */ = PerceptualSmoothnessToPerceptualRoughness(Smoothness);
|
|
g.reflUVW = reflect(-worldViewDir, Normal);
|
|
return g;
|
|
}
|
|
inline void ResetUnityLight(out UnityLight outLight)
|
|
{
|
|
outLight.color = half3(0, 0, 0);
|
|
outLight.dir = half3(0, 1, 0); // Irrelevant direction, just not null
|
|
outLight.ndotl = 0; // Not used
|
|
}
|
|
inline void ResetUnityGI(out UnityGI outGI)
|
|
{
|
|
ResetUnityLight(outGI.light);
|
|
outGI.indirect.diffuse = 0;
|
|
outGI.indirect.specular = 0;
|
|
}
|
|
half3 UnpackScaleNormalRGorAG(half4 packednormal, half bumpScale)
|
|
{
|
|
#if defined(UNITY_NO_DXT5nm)
|
|
half3 normal = packednormal.xyz * 2 - 1;
|
|
#if (SHADER_TARGET >= 30)
|
|
normal.xy *= bumpScale;
|
|
#endif
|
|
return normal;
|
|
#elif defined(UNITY_ASTC_NORMALMAP_ENCODING)
|
|
half3 normal;
|
|
normal.xy = (packednormal.wy * 2 - 1);
|
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
|
normal.xy *= bumpScale;
|
|
return normal;
|
|
#else
|
|
packednormal.x *= packednormal.w;
|
|
half3 normal;
|
|
normal.xy = (packednormal.xy * 2 - 1);
|
|
#if (SHADER_TARGET >= 30)
|
|
normal.xy *= bumpScale;
|
|
#endif
|
|
normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
|
|
return normal;
|
|
#endif
|
|
}
|
|
half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
|
|
{
|
|
return UnpackScaleNormalRGorAG(packednormal, bumpScale);
|
|
}
|
|
|
|
half3x3 CreateTangentToWorldPerVertex(half3 normal, half3 tangent, half tangentSign)
|
|
{
|
|
// For odd-negative scale transforms we need to flip the sign
|
|
half sign = tangentSign * unity_WorldTransformParams.w;
|
|
half3 binormal = cross(normal, tangent) * sign;
|
|
return half3x3(tangent, binormal, normal);
|
|
}
|
|
// ----------------------------------------------------------------------------
|
|
inline half3 DecodeHDR (half4 data, half4 decodeInstructions)
|
|
{
|
|
// Take into account texture alpha if decodeInstructions.w is true(the alpha value affects the RGB channels)
|
|
half alpha = decodeInstructions.w * (data.a - 1.0) + 1.0;
|
|
// If Linear mode is not supported we can skip exponent part
|
|
#if defined(UNITY_COLORSPACE_GAMMA)
|
|
return (decodeInstructions.x * alpha) * data.rgb;
|
|
#else
|
|
#if defined(UNITY_USE_NATIVE_HDR)
|
|
return decodeInstructions.x * data.rgb; // Multiplier for future HDRI relative to absolute conversion.
|
|
#else
|
|
return (decodeInstructions.x * pow(alpha, decodeInstructions.y)) * data.rgb;
|
|
#endif
|
|
#endif
|
|
}
|
|
inline half3 PreMultiplyAlpha (half3 diffColor, half alpha, half oneMinusReflectivity, out half outModifiedAlpha)
|
|
{
|
|
diffColor *= alpha;
|
|
outModifiedAlpha = 1-oneMinusReflectivity + alpha*oneMinusReflectivity;
|
|
return diffColor;
|
|
}
|
|
inline half OneMinusReflectivityFromMetallic(half metallic)
|
|
{
|
|
half oneMinusDielectricSpec = 0.56;
|
|
return oneMinusDielectricSpec - metallic * oneMinusDielectricSpec;
|
|
}
|
|
inline half3 DiffuseAndSpecularFromMetallic (half3 albedo, half metallic, out half3 specColor, out half oneMinusReflectivity)
|
|
{
|
|
specColor = lerp (UNITY_LIGHTMODEL_AMBIENT.xyz, albedo, metallic);
|
|
oneMinusReflectivity = OneMinusReflectivityFromMetallic(metallic);
|
|
return albedo * oneMinusReflectivity;
|
|
}
|
|
inline UnityGI UnityGI_Base(UnityGIInput data, half occlusion, half3 normalWorld)
|
|
{
|
|
UnityGI o_gi;
|
|
ResetUnityGI(o_gi);
|
|
o_gi.light = data.light;
|
|
o_gi.light.color *= data.atten;
|
|
o_gi.indirect.diffuse *= occlusion;
|
|
return o_gi;
|
|
}
|
|
inline half3 UnityGI_IndirectSpecular(UnityGIInput data, half occlusion, Unity_GlossyEnvironmentData glossIn)
|
|
{
|
|
half3 specular;
|
|
specular = unity_IndirectSpecColor.rgb;
|
|
return specular * occlusion;
|
|
}
|
|
inline half3 UnityGI_IndirectSpecular(UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
|
|
{
|
|
return UnityGI_IndirectSpecular(data, occlusion, glossIn);
|
|
}
|
|
inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half3 normalWorld)
|
|
{
|
|
return UnityGI_Base(data, occlusion, normalWorld);
|
|
}
|
|
inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half3 normalWorld, Unity_GlossyEnvironmentData glossIn)
|
|
{
|
|
UnityGI o_gi = UnityGI_Base(data, occlusion, normalWorld);
|
|
o_gi.indirect.specular = UnityGI_IndirectSpecular(data, occlusion, glossIn);
|
|
return o_gi;
|
|
}
|
|
inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld, bool reflections)
|
|
{
|
|
Unity_GlossyEnvironmentData g = UnityGlossyEnvironmentSetup(smoothness, data.worldViewDir, normalWorld, float3(0, 0, 0));
|
|
return UnityGlobalIllumination(data, occlusion, normalWorld, g);
|
|
}
|
|
inline UnityGI UnityGlobalIllumination (UnityGIInput data, half occlusion, half smoothness, half3 normalWorld)
|
|
{
|
|
bool sampleReflections = true;
|
|
return UnityGlobalIllumination (data, occlusion, smoothness, normalWorld, sampleReflections);
|
|
}
|
|
inline half3 GetSpecularColorGGX_Smoothness (half ndotH, half ndotL, half ldotH, half3 specularColor, half smoothness, half powFac = 64, half ggxClamp = 3)
|
|
{
|
|
half3 specular = 0;
|
|
#if defined(_SG_GGX_SMOOTH)
|
|
half perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness (smoothness);
|
|
perceptualRoughness = max(0.08, perceptualRoughness);
|
|
half roughness = PerceptualSmoothnessToPerceptualRoughness(perceptualRoughness);
|
|
half a = roughness;
|
|
half a2 = a * a;
|
|
half d = ndotH * ndotH * (a2 - 1) + 1.0001;
|
|
half specularTerm = a2 / (max(0.2, ldotH * ldotH) * (roughness + 0.5) * (d * d) * powFac);
|
|
specularTerm = specularTerm - 1e-4h;
|
|
specularTerm = clamp(specularTerm, 0, ggxClamp);
|
|
specular = specularTerm * specularColor.rgb;
|
|
#endif
|
|
return specular;
|
|
}
|
|
inline half3x3 GetDiffuseColor(half smoothness, half3 specularColor, half3 mainColor,
|
|
half3 worldNormal, half lightAtten, half3 NDotL)
|
|
{
|
|
half3 lightColor = lerp(half3(0,0,0), GetMainLight().color.rgb, lightAtten * NDotL);
|
|
specularColor = lerp(half3(0,0,0), GetMainLight().color.rgb, lightAtten) * specularColor;
|
|
half3 diffuse = mainColor * lightColor;
|
|
#if defined(SGAME_WET) && defined(SGAME_QUALITY_PERFECT) || defined(SGAME_QUALITY_HIGH)
|
|
mainColor = lerp(mainColor, mainColor * _SG_WetColor, _SG_WetFactor);
|
|
specularColor = lerp(specularColor, _SG_WetSpecularColor * _SG_WetSpecularStrength, _SG_WetFactor);
|
|
smoothness = lerp(lerp(smoothness, _SG_WetSmoothness, _SG_WetFactor), smoothness, smoothness > _SG_WetSmoothness);
|
|
half thunderNDotL = saturate(dot(worldNormal, _SG_ThunderDirection));
|
|
half3 thunderDiffuse = mainColor * lerp(half3(0, 0, 0), _SG_ThunderColor, max(lightAtten,0.1)) * thunderNDotL * _SG_ThunderStrength;
|
|
diffuse += thunderDiffuse;
|
|
#endif
|
|
|
|
half3x3 matrixColor;
|
|
matrixColor[0] = diffuse;
|
|
matrixColor[1] = specularColor;
|
|
matrixColor[2] = half3(smoothness, 0, 0);
|
|
return matrixColor;
|
|
}
|
|
inline half3 GetSumLightingColorSpecGGX_Smoothness(half3 mainColor, half3 specularColor, half3 shLight,
|
|
half3 worldNormal, half3 worldPos, half smoothness, half lightAtten, half powFac = 64, half ggxClamp = 3, half intensity = 1)
|
|
{
|
|
half3 worldViewDir = normalize(GetCameraPositionWS() - worldPos);
|
|
half3 worldLightDir = normalize(GetMainLight().direction);
|
|
half3 halfDir = normalize(worldLightDir + worldViewDir);
|
|
half ndotH = max(dot(worldNormal, halfDir), 0);
|
|
half NDotL = max(dot(worldNormal, worldLightDir), 0);
|
|
half ldotH = max(dot(worldLightDir, halfDir), 0);
|
|
|
|
half3x3 colorMatrix = GetDiffuseColor(smoothness, specularColor, mainColor, worldNormal, lightAtten, NDotL);
|
|
specularColor = colorMatrix[1];
|
|
smoothness = colorMatrix[2].x;
|
|
|
|
half3 ambient = mainColor * 0.5;
|
|
half3 diffuse = colorMatrix[0];
|
|
half3 specular = GetSpecularColorGGX_Smoothness(ndotH, NDotL, ldotH, specularColor, smoothness, powFac, ggxClamp);
|
|
return ambient + diffuse + specular * intensity;
|
|
}
|
|
inline half SGameShadowAtten(half atten)
|
|
{
|
|
return max(atten, 0.2);
|
|
}
|
|
inline half SGameStylizedAtten(half atten, half _DoubleSGameShadowAtten)
|
|
{
|
|
half stylizedAtten = (atten + _DoubleSGameShadowAtten) * 0.5;
|
|
stylizedAtten = saturate(stylizedAtten);
|
|
return stylizedAtten;
|
|
}
|
|
inline half SGameRoughness(half smoothness, out half perceptualRoughness )
|
|
{
|
|
perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness (smoothness);
|
|
perceptualRoughness = max(0.001, perceptualRoughness);
|
|
half roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
|
|
return roughness;
|
|
}
|
|
inline half SGameDirectSpecular(half3 normal, half3 viewDir, half NDotL, half metallic, half nh, half lh)
|
|
{
|
|
half3 backfaceLightDir = viewDir;
|
|
half3 backfaceHalfDir = viewDir;
|
|
half backface_nh = saturate(dot(normal, backfaceHalfDir));
|
|
half backface_lh = saturate(dot(backfaceLightDir, backfaceHalfDir));
|
|
//half notBackface = smoothstep(0,0.5,NDotL * 0.5 + 0.5); //0背光 -> 1受光
|
|
half notBackface = smoothstep(-1,0.5,NDotL); //0背光 -> 1受光
|
|
//nh = lerp(backface_nh, nh, notBackface);
|
|
//lh = lerp(backface_lh, lh, notBackface);
|
|
half isBackface = 1 - smoothstep(-1,0.5,NDotL);
|
|
//half ratio = isBackface * step(0.5, metallic);
|
|
half ratio = isBackface * lerp(0.3,1,metallic);
|
|
nh = lerp(nh, backface_nh, ratio);
|
|
lh = lerp(lh, backface_lh, ratio);
|
|
return isBackface;
|
|
}
|
|
inline half3 SGameStylizedSpecularColor( half3 specularColor, half metallic )
|
|
{
|
|
half3 linearSpecularColor = specularColor * specularColor;
|
|
specularColor = lerp( linearSpecularColor, specularColor, metallic );
|
|
return specularColor;
|
|
}
|
|
#endif |