//Unity Toon Shader/HDRP //nobuyuki@unity3d.com //toshiyuki@unity3d.com (Universal RP/HDRP) #ifndef UCTS_HDRP_INCLUDED #define UCTS_HDRP_INCLUDED #define UCTS_HDRP 1 #define UTS_LAYER_VISIBILITY #ifndef DIRECTIONAL # define DIRECTIONAL #endif #define FP_BUFFER 1 #if FP_BUFFER #define SATURATE_IF_SDR(x) (x) #define SATURATE_BASE_COLOR_IF_SDR(x) (x) #else #define SATURATE_IF_SDR(x) saturate(x) #define SATURATE_BASE_COLOR_IF_SDR(x) saturate(x) #endif struct UTSData { float3 viewDirection; float3 normalDirection; fixed cameraDir; float cameraRoll; fixed signMirror; }; //#define UTSDATA_ZERO_INITIALIZE (UTSData) struct UTSLightData { float3 lightDirection; float3 lightColor; float diffuseDimmer; float specularDimmer; float3 shadowTint; float penumbraTint; float shadowValue; }; struct UTSAggregateLighting { float3 directDiffuse; float3 directSpecular; float3 indirectDiffuse; float3 indirectSpecular; }; float3 AccumulateAggregateLighting(UTSAggregateLighting aggregateLighting) { return SATURATE_IF_SDR(aggregateLighting.directDiffuse + aggregateLighting.directSpecular) + aggregateLighting.indirectDiffuse + aggregateLighting.indirectSpecular; } #if defined(UNITY_PASS_PREPASSBASE) || defined(UNITY_PASS_DEFERRED) || defined(UNITY_PASS_SHADOWCASTER) #undef FOG_LINEAR #undef FOG_EXP #undef FOG_EXP2 #endif #if 1 // Legacy for compatibility with existing shaders inline bool IsGammaSpace() { #ifdef UNITY_COLORSPACE_GAMMA return true; #else return false; #endif } // normal should be normalized, w=1.0 half3 SHEvalLinearL0L1(half4 normal) { half3 x; // Linear (L1) + constant (L0) polynomial terms x.r = dot(unity_SHAr, normal); x.g = dot(unity_SHAg, normal); x.b = dot(unity_SHAb, normal); return x; } // normal should be normalized, w=1.0 half3 SHEvalLinearL2(half4 normal) { half3 x1, x2; // 4 of the quadratic (L2) polynomials half4 vB = normal.xyzz * normal.yzzx; x1.r = dot(unity_SHBr, vB); x1.g = dot(unity_SHBg, vB); x1.b = dot(unity_SHBb, vB); // Final (5th) quadratic (L2) polynomial half vC = normal.x * normal.x - normal.y * normal.y; x2 = unity_SHC.rgb * vC; return x1 + x2; } // normal should be normalized, w=1.0 // output in active color space half3 ShadeSH9(half4 normal) { // Linear + constant polynomial terms half3 res = SHEvalLinearL0L1(normal); // Quadratic polynomials res += SHEvalLinearL2(normal); # ifdef UNITY_COLORSPACE_GAMMA res = LinearToGammaSpace(res); # endif return res; } float3 DecodeLightProbe(float3 N) { return ShadeSH9(float4(N, 1)); } inline float GammaToLinearSpaceExact(float value) { if (value <= 0.04045F) return value / 12.92F; else if (value < 1.0F) return pow((value + 0.055F) / 1.055F, 2.4F); else return pow(value, 2.2F); } inline float3 GammaToLinearSpace(float3 sRGB) { // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1 return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h); // Precise version, useful for debugging. //return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b)); } inline float LinearToGammaSpaceExact(float value) { if (value <= 0.0F) return 0.0F; else if (value <= 0.0031308F) return 12.92F * value; else if (value < 1.0F) return 1.055F * pow(value, 0.4166667F) - 0.055F; else return pow(value, 0.45454545F); } inline float3 LinearToGammaSpace(float3 linRGB) { linRGB = max(linRGB, float3(0.h, 0.h, 0.h)); // An almost-perfect approximation from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1 return max(1.055h * pow(linRGB, 0.416666667h) - 0.055h, 0.h); // Exact version, useful for debugging. //return half3(LinearToGammaSpaceExact(linRGB.r), LinearToGammaSpaceExact(linRGB.g), LinearToGammaSpaceExact(linRGB.b)); } #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) #define UNITY_FOG_COORDS(idx) UNITY_FOG_COORDS_PACKED(idx, float1) #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) // mobile or SM2.0: calculate fog factor per-vertex #define UNITY_TRANSFER_FOG(o,outpos) UNITY_CALC_FOG_FACTOR((outpos).z); o.fogCoord.x = unityFogFactor #else // SM3.0 and PC/console: calculate fog distance per-vertex, and fog factor per-pixel #define UNITY_TRANSFER_FOG(o,outpos) o.fogCoord.x = (outpos).z #endif #else #define UNITY_FOG_COORDS(idx) #define UNITY_TRANSFER_FOG(o,outpos) #endif #define UNITY_FOG_LERP_COLOR(col,fogCol,fogFac) col.rgb = lerp((fogCol).rgb, (col).rgb, saturate(fogFac)) #if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2) #if (SHADER_TARGET < 30) || defined(SHADER_API_MOBILE) // mobile or SM2.0: fog factor was already calculated per-vertex, so just lerp the color #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_FOG_LERP_COLOR(col,fogCol,(coord).x) #else // SM3.0 and PC/console: calculate fog factor and lerp fog color #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) UNITY_CALC_FOG_FACTOR((coord).x); UNITY_FOG_LERP_COLOR(col,fogCol,unityFogFactor) #endif #else #define UNITY_APPLY_FOG_COLOR(coord,col,fogCol) #endif #ifdef UNITY_PASS_FORWARDADD #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,fixed4(0,0,0,0)) #else #define UNITY_APPLY_FOG(coord,col) UNITY_APPLY_FOG_COLOR(coord,col,unity_FogColor) #endif #endif //#if false #ifdef DIRECTIONAL #define LIGHTING_COORDS(idx1,idx2) SHADOW_COORDS(idx1) #define TRANSFER_VERTEX_TO_FRAGMENT(a) TRANSFER_SHADOW(a) #define LIGHT_ATTENUATION(a) SHADOW_ATTENUATION(a) #endif // Transforms 2D UV by scale/bias property //#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw) #define UCTS_TEXTURE2D(tex,name) SAMPLE_TEXTURE2D(tex,sampler##tex,TRANSFORM_TEX(name, tex)); inline float4 UnityObjectToClipPosInstanced(in float3 pos) { // return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorldArray[unity_InstanceID], float4(pos, 1.0))); // todo. right? return mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, float4(pos, 1.0))); } inline float4 UnityObjectToClipPosInstanced(float4 pos) { return UnityObjectToClipPosInstanced(pos.xyz); } #define UnityObjectToClipPos UnityObjectToClipPosInstanced inline float3 UnityObjectToWorldNormal( in float3 norm ) { #ifdef UNITY_ASSUME_UNIFORM_SCALING return UnityObjectToWorldDir(norm); #else // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)} return normalize(mul(norm, (float3x3)UNITY_MATRIX_M)); #endif } // normal should be normalized, w=1.0 float3 SHEvalLinearL0L1 (float4 normal) { float3 x; // Linear (L1) + constant (L0) polynomial terms x.r = dot(unity_SHAr,normal); x.g = dot(unity_SHAg,normal); x.b = dot(unity_SHAb,normal); return x; } // normal should be normalized, w=1.0 float3 SHEvalLinearL2 (float4 normal) { float3 x1, x2; // 4 of the quadratic (L2) polynomials float4 vB = normal.xyzz * normal.yzzx; x1.r = dot(unity_SHBr,vB); x1.g = dot(unity_SHBg,vB); x1.b = dot(unity_SHBb,vB); // Final (5th) quadratic (L2) polynomial half vC = normal.x*normal.x - normal.y*normal.y; x2 = unity_SHC.rgb * vC; return x1 + x2; } // normal should be normalized, w=1.0 // output in active color space float3 ShadeSH9 (float4 normal) { // Linear + constant polynomial terms float3 res = SHEvalLinearL0L1 (normal); // Quadratic polynomials res += SHEvalLinearL2 (normal); # ifdef UNITY_COLORSPACE_GAMMA res = LinearToGammaSpace (res); # endif return res; } float rateR = 0.299; float rateG = 0.587; float rateB = 0.114; float3 SampleBakedGI_UTS(float3 positionRWS, float3 normalWS, float2 uvStaticLightmap, float2 uvDynamicLightmap, bool needToIncludeAPV = false) { float3 bakeDiffuseLighting = float3(0, 0, 0); float3 backBakeDiffuseLighting = float3(0, 0, 0); float3 backNormalWS = float3(0, 0, 0); #if !defined(_SURFACE_TYPE_TRANSPARENT) && (SHADERPASS != SHADERPASS_RAYTRACING_INDIRECT) && (SHADERPASS != SHADERPASS_RAYTRACING_GBUFFER) if (_IndirectDiffuseMode != INDIRECTDIFFUSEMODE_OFF #if (SHADERPASS == SHADERPASS_GBUFER) && _IndirectDiffuseMode != INDIRECTDIFFUSEMODE_MIXED && _ReflectionsMode != REFLECTIONSMODE_MIXED #endif ) return bakeDiffuseLighting; #endif #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON) EvaluateLightmap(positionRWS, normalWS, backNormalWS, uvStaticLightmap, uvDynamicLightmap, bakeDiffuseLighting, backBakeDiffuseLighting); #elif (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)) if (needToIncludeAPV) { EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(positionRWS), normalWS, backNormalWS, GetWorldSpaceNormalizeViewDir(positionRWS), 0.0, bakeDiffuseLighting, backBakeDiffuseLighting); } #else EvaluateLightProbeBuiltin(positionRWS, normalWS, backNormalWS, bakeDiffuseLighting, backBakeDiffuseLighting); #if defined(SHADER_STAGE_RAY_TRACING) bakeDiffuseLighting *= _RayTracingAmbientProbeDimmer; backBakeDiffuseLighting *= _RayTracingAmbientProbeDimmer; #endif #endif return bakeDiffuseLighting; } float3 SampleBakedGI_UTS_OutLine(float3 positionRWS, float3 normalWS, float2 uvStaticLightmap, float2 uvDynamicLightmap) { float3 bakeDiffuseLighting = float3(0, 0, 0); float3 backBakeDiffuseLighting = float3(0, 0, 0); float3 backNormalWS = float3(0, 0, 0); #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON) EvaluateLightmap(positionRWS, normalWS, backNormalWS, uvStaticLightmap, uvDynamicLightmap, bakeDiffuseLighting, backBakeDiffuseLighting); #elif (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)) EvaluateAdaptiveProbeVolume(GetAbsolutePositionWS(positionRWS), normalWS, backNormalWS, GetWorldSpaceNormalizeViewDir(positionRWS), 0.0, bakeDiffuseLighting, backBakeDiffuseLighting); #else EvaluateLightProbeBuiltin(positionRWS, normalWS, backNormalWS, bakeDiffuseLighting, backBakeDiffuseLighting); #if defined(SHADER_STAGE_RAY_TRACING) bakeDiffuseLighting *= _RayTracingAmbientProbeDimmer; backBakeDiffuseLighting *= _RayTracingAmbientProbeDimmer; #endif #endif return bakeDiffuseLighting; } #endif //#ifndef UCTS_HDRP_INCLUDED