#ifndef SGAME_UNITY_STANDARD_INPUT_INCLUDED #define SGAME_UNITY_STANDARD_INPUT_INCLUDED #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" //-------------------------------------------------------------------------------- #if defined(UNITY_PASS_FORWARDBASE) #define SGAME_ENV_MAP_STRENGTH 1 #define SGAME_TONEMAPPING_ACES 1 #define SGAME_LINEAR_DIFFUSE_COLOR 1 #define SGAME_TONEMAPPING_LIGHT_BOOST 1 #define SGAME_STYLIZED_ATTEN 1 #define SGAME_VLIGHT_DIFFUSE 1 #define SGAME_VLIGHT_SPECULAR 1 #define SGAME_TONEMAPPING_GI_DIFFUSE_ATTEN 1 #endif #if defined(UNITY_PASS_FORWARDADD) #define SGAME_LINEAR_DIFFUSE_COLOR 1 #endif #define SGAME_VLIGHT 1 #define SGAME_VLIGHT_DIFFUSE 1 #if !defined(SGAME_QUALITY_PERFECT) && !defined(SGAME_QUALITY_HIGH) #define _NORMALMAP_ON 0 #define _EMISSION_ON 0 #endif #if defined(_SKIN_CALCULATION) #define SGAME_ENV_MAP 0 #endif // Directional lightmaps & Parallax require tangent space too #if (_NORMALMAP_ON || DIRLIGHTMAP_COMBINED || _PARALLAXMAP) #define _TANGENT_TO_WORLD 1 #endif //------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------- TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NrmMap); SAMPLER(sampler_NrmMap); TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap); TEXTURE2D(_SkinMask); SAMPLER(sampler_SkinMask); #if defined(_SKIN_CALCULATION) TEXTURE2D(_BeckmannTex); SAMPLER(sampler_BeckmannTex); #endif #if defined(_BLINNING_PHONG) TEXTURECUBE(_IBLCubeMap); SAMPLER(sampler_IBLCubeMap); #endif #if defined(_ANISOGGX_ON) TEXTURE2D(_AnisotrophicMask); SAMPLER(sampler_AnisotrophicMask); #endif CBUFFER_START(UnityPerMaterial) half4 _Color; half _Cutoff; half _SpecularBloomAdd; float4 _MainTex_ST; half4 _NrmMap_ST; half _BumpScale; half _MetallicMapScale; half _GlossMapScale; half _OcclusionScale; #if defined(_SKIN_CALCULATION) half _SkinSpecIntensity; half _SkinRoughness; half4 _SkinColor; #endif #if defined(_BLINNING_PHONG) half _CubeMapIntensity; half _CubeMapRot; #endif #if defined(_ANISOGGX_ON) half _AnisotrophicScale; half _AnisotrophicMetallic; half _AnisotrophicSmooth; #endif half _EmissiveMapScale; half4 _EmissiveColor; half _IBLInensity; half _DiffuseWrap; half _ColorLerpMask; half4 _LerpMaskColor; half _HighLightLerp; half4 _HighLightLerpColor; half _BlinnphongIntensity; CBUFFER_END // Input functions//------------------------------------------------------------------ struct VertexInput { float4 vertex : POSITION; half3 normal : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; #if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META) float2 uv2 : TEXCOORD2; #endif half4 tangent : TANGENT; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct FragmentCommonData { // Note: smoothness & oneMinusReflectivity for optimization purposes, mostly for DX9 SM2.0 level. // Most of the math is being done on these (1-x) values, and that saves a few precious ALU slots. half4 albedo; half3 diffColor, specColor, emissive; half4 mainColor; half oneMinusReflectivity, smoothness; half3 normalWorld, eyeVec; half alpha; float3 posWorld; half skinDepth; half metallic; half isSkin; half anisotrophic; half occlusion; }; 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 WorldNormal(half4 tan2world[3]) { return normalize(tan2world[2].xyz); } // counterpart for NormalizePerPixelNormal // skips normalization per-vertex and expects normalization to happen per-pixel 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 } 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); } //------------------------------------------------------------------------------------- UnityLight MainLight () { UnityLight l; l.color = GetMainLight().color.rgb; 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 // shadow the light 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; } 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 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 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); } 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); } //------------------------------------------------------------------------------------- float4 TexCoords(VertexInput v) { float4 texcoord; texcoord.xy = TRANSFORM_TEX(v.uv0, _MainTex); // Always source from uv0 #ifdef _INVERT_UV texcoord.y = 1 - texcoord.y; #endif return texcoord; } inline half3 SGameSkinAlbedo(half isSkin, half3 albedo, half3 diffColor ) { half3 skinDiffColor = lerp(diffColor, albedo, isSkin); return skinDiffColor; } inline half IsSkin(half skinParam) { return step(0.5, skinParam); } //------------------------------------------------------------------------------------- // Common fragment setup #ifdef _PARALLAXMAP #define IN_VIEWDIR4PARALLAX(i) NormalizePerPixelNormal(half3(i.tangentToWorldAndPackedData[0].w,i.tangentToWorldAndPackedData[1].w,i.tangentToWorldAndPackedData[2].w)) #define IN_VIEWDIR4PARALLAX_FWDADD(i) NormalizePerPixelNormal(i.viewDirForParallax.xyz) #else #define IN_VIEWDIR4PARALLAX(i) half3(0,0,0) #define IN_VIEWDIR4PARALLAX_FWDADD(i) half3(0,0,0) #endif #ifdef _TANGENT_TO_WORLD half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) { half3 t = tan2world[0].xyz; half3 b = tan2world[1].xyz; half3 n = tan2world[2].xyz; #if UNITY_TANGENT_ORTHONORMALIZE n = NormalizePerPixelNormal(n); t = normalize (t - n * dot(t, n)); half3 newB = cross(n, t); b = newB * sign (dot (newB, b)); #endif return half3x3(t, b, n); } #else half3x3 ExtractTangentToWorldPerPixel(half4 tan2world[3]) { return half3x3(0,0,0,0,0,0,0,0,0); } #endif #ifdef _NORMALMAP_ON half3 NormalInTangentSpace(float4 texcoords) { half3 normalTangent = SAMPLE_TEXTURE2D(_NrmMap, sampler_NrmMap, texcoords.xy).rgb * 2 - 1; normalTangent.xy *= _BumpScale; return normalTangent; } #endif half3 PerPixelWorldNormal(float4 i_tex, half4 tangentToWorld[3]) { #ifdef _NORMALMAP_ON half3 tangent = tangentToWorld[0].xyz; half3 binormal = tangentToWorld[1].xyz; half3 normal = tangentToWorld[2].xyz; half3 normalTangent = NormalInTangentSpace(i_tex); half3 normalWorld = NormalizePerPixelNormal(tangent * normalTangent.x + binormal * normalTangent.y + normal * normalTangent.z); // @TODO: see if we can squeeze this normalize on SM2.0 as well #else half3 normalWorld = normalize(tangentToWorld[2].xyz); #endif return normalWorld; } half4 Albedo(float4 texcoords) { half4 main_color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, texcoords.xy).rgba; #if defined(_SKIN_CALCULATION) half3 colorAddLerp = lerp(1, _LerpMaskColor.rgb * 0.8, main_color.a); #else half3 colorAddLerp = lerp(_Color.rgb, _LerpMaskColor.rgb * 0.8, main_color.a); #endif half3 albedo = main_color.rgb * colorAddLerp; return half4(albedo, main_color.a); } half Alpha(float2 uv) { return SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv).a * _Color.a; } half4 MetallicGloss(float2 uv) { half4 mg_skin; mg_skin = SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv).ragb; mg_skin.r *= _MetallicMapScale + 0.03; mg_skin.g *= _GlossMapScale; #if defined(_ANISOGGX_ON) mg_skin.b *= _AnisotrophicScale; #endif mg_skin.a = pow(mg_skin.a, _OcclusionScale); mg_skin = saturate(mg_skin); return mg_skin; } float4 Parallax (float4 texcoords, half3 viewDir) { return texcoords; } float4 GetMask2(float2 texcoord) { return SAMPLE_TEXTURE2D(_SkinMask, sampler_SkinMask, texcoord); } #if defined(_SKIN_CALCULATION) float4 BeckmannTexCol (float2 texcoord) { return SAMPLE_TEXTURE2D(_BeckmannTex, sampler_BeckmannTex, texcoord); } #endif 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); } #endif