#ifndef UCTS_HDRP_INCLUDED #define UCTS_HDRP_INCLUDED #include "Packages/com.misaki.hdrp-toon/Runtime/Shaders/Includes/Common/UtsCommon.hlsl" #define UTS_LAYER_VISIBILITY #define FP_BUFFER 1 #if _PBR_MODE_OFF #undef _MASKMAP #undef _ANISOTROPYMAP #undef _SPECULARCOLORMAP #endif #if defined(UNITY_PASS_PREPASSBASE) || defined(UNITY_PASS_DEFERRED) || defined(UNITY_PASS_SHADOWCASTER) #undef FOG_LINEAR #undef FOG_EXP #undef FOG_EXP2 #endif #define Uts_ColorSpaceDielectricSpec half4(0.04, 0.04, 0.04, 1.0 - 0.04) struct UTSSurfaceData { uint surfaceFeatures; real3 baseColor; real3 firstShadingColor; real3 secondShadingColor; real alpha; float3 normalWS; real perceptualSmoothness; real metallic; real specularOcclusion; real ambientOcclusion; real3 specularColor; float3 geomNormalWS; float3 tangentWS; real4 subsurfaceColor; real anisotropy; }; struct UtsBSDFData { uint surfaceFeatures; real3 diffuseColor; real3 firstShadingDiffuseColor; real3 secondShadingDiffuseColor; real3 fresnel0; real fresnel90; real reflectivity; real ambientOcclusion; real specularOcclusion; real perceptualRoughness; real3 subsurfaceColor; float3 geomNormalWS; float3 normalWS; float3 tangentWS; float3 bitangentWS; real anisotropy; real roughnessT; real roughnessB; }; bool IsNonZeroBSDF(float3 L, float3 normalWS) { #if _MATERIAL_TYPE_FACE || _USE_SHADING_RAMP_MAP_ON return true; #else float NdotL = dot(normalWS, L); return NdotL > 0.0; #endif } bool IsNonZeroBSDF(float3 L, UtsBSDFData bsdfData) { return IsNonZeroBSDF(L, bsdfData.normalWS); } UTSSurfaceData ConvertSurfaceDataToUTSSurfaceData(SurfaceData surfaceData) { UTSSurfaceData output; ZERO_INITIALIZE(UTSSurfaceData, output); output.surfaceFeatures = surfaceData.materialFeatures; output.baseColor = surfaceData.baseColor; output.alpha = 1.0; output.normalWS = surfaceData.normalWS; output.perceptualSmoothness = surfaceData.perceptualSmoothness; output.metallic = surfaceData.metallic; output.specularOcclusion = surfaceData.specularOcclusion; output.ambientOcclusion = surfaceData.ambientOcclusion; output.specularColor = surfaceData.specularColor; output.geomNormalWS = surfaceData.geomNormalWS; output.tangentWS = surfaceData.tangentWS; output.subsurfaceColor.rgb = surfaceData.transmittanceColor; output.subsurfaceColor.a = surfaceData.subsurfaceMask; output.anisotropy = surfaceData.anisotropy; return output; } UTSSurfaceData GetUTSSurfaceData(FragInputs input, float3 V) { // Not zero initialized to make sure all fields are set. UTSSurfaceData output; output.surfaceFeatures = _SurfaceFeatures; float4 mainTexture = SAMPLE_TEXTURE2D(_BaseColorMap, sampler_BaseColorMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)); output.baseColor = mainTexture.rgb * _BaseColor.rgb; output.alpha = mainTexture.a; #if _USE_SHADING_RAMP_MAP_ON output.firstShadingColor = 0.0; output.secondShadingColor = 0.0; #else float4 firstShadingTexture = SAMPLE_TEXTURE2D(_1stShadeColorMap, sampler_BaseColorMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)); output.firstShadingColor = lerp(firstShadingTexture.rgb, mainTexture.rgb, _UseBaseAs1st) * _1stShadeColor.rgb; #if _SHADING_MODE_STANDARD float4 secondShadingTexture = SAMPLE_TEXTURE2D(_2ndShadeColorMap, sampler_BaseColorMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)); output.secondShadingColor = lerp(secondShadingTexture.rgb, output.firstShadingColor, _Use1stAs2nd) * _2ndShadeColor.rgb; #else output.secondShadingColor = 0.0; #endif #endif float4 normalLocal = float4(0, 0, 1.0, 1.0); #if _NORMALMAP // if (_Use_SSSLut) // { // normalLocal = SAMPLE_TEXTURE2D_LOD(_NormalMap, sampler_NormalMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap), _SSSIntensity); // } // else { normalLocal = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)); normalLocal.rgb = UnpackNormalScale(normalLocal, _NormalScale); } #endif float3 normalWS = normalize(mul(normalLocal.rgb, input.tangentToWorld)); #if _PBR_MODE_OFF float smoothness = 0.0; float metallic = 0.0; #else float smoothness = _Smoothness; float metallic = _Metallic; #endif float ao = 1.0; float3 specularColor = 1; float anisotropy = 0; #ifdef _MASKMAP float4 _MaskMap_var = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)); metallic = _MaskMap_var.x; metallic = lerp(_MetallicRemapMin, _MetallicRemapMax, metallic); ao = _MaskMap_var.y; ao = lerp(_AORemapMin, _AORemapMax, ao); smoothness = _MaskMap_var.w; smoothness = lerp(_SmoothnessRemapMin, _SmoothnessRemapMax, smoothness); #endif #ifdef _ANISOTROPYMAP anisotropy = SAMPLE_TEXTURE2D(_AnisotropyMap, sampler_AnisotropyMap, TRANSFORM_TEX(input.texCoord0, _AnisotropyMap)).r; #if _PBR_Mode_KK anisotropy += _Anisotropy - 0.5; #else anisotropy *= _Anisotropy; #endif #else anisotropy = 1.0; anisotropy *= _Anisotropy; #endif #ifdef _PBR_Mode_KK metallic = 0.0; smoothness *=_BSDFContribution; #endif // TODO: Specular color is not handle correctly. #ifdef _PBR_MODE_TOON metallic = 0.0; specularColor = _SpecularColor; #ifdef _SPECULARCOLORMAP specularColor *= SAMPLE_TEXTURE2D(_SpecularColorMap, sampler_SpecularColorMap, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)).rgb; #endif #endif output.metallic = metallic; output.ambientOcclusion = ao; output.specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(dot(normalWS, V), ao, PerceptualRoughnessToRoughness(1 - smoothness)); output.perceptualSmoothness = smoothness; output.normalWS = normalWS; output.specularColor = specularColor; output.geomNormalWS = input.tangentToWorld[2]; output.tangentWS = Orthonormalize(input.tangentToWorld[0].rgb, normalWS); // output.subsurfaceColor = SAMPLE_TEXTURE2D(_SSSLutMap, s_linear_clamp_sampler, TRANSFORM_TEX(input.texCoord0, _BaseColorMap)) * _SSSIntensity; output.subsurfaceColor = 0.0; output.anisotropy = anisotropy; return output; } UtsBSDFData ConvertUTSSurfaceDataToUTSBSDFData(UTSSurfaceData surfaceData) { UtsBSDFData output; output.surfaceFeatures = surfaceData.surfaceFeatures; #if _PBR_MODE_TOON float m = Max3(surfaceData.specularColor.r, surfaceData.specularColor.g, surfaceData.specularColor.b); #else float m = surfaceData.metallic; #endif output.diffuseColor = UtsComputeDiffuseColor(surfaceData.baseColor, m, _Minimal_Diffuse_Contribution); output.firstShadingDiffuseColor = UtsComputeDiffuseColor(surfaceData.firstShadingColor, m, _Minimal_Diffuse_Contribution); output.secondShadingDiffuseColor = UtsComputeDiffuseColor(surfaceData.secondShadingColor, m, _Minimal_Diffuse_Contribution); #if _PBR_MODE_OFF output.fresnel0 = 0.22; #elif _PBR_MODE_TOON output.fresnel0 = surfaceData.specularColor; #else output.fresnel0 = ComputeFresnel0(surfaceData.baseColor, surfaceData.metallic, 0.22); #endif output.fresnel90 = ComputeF90(output.fresnel0); output.reflectivity = (1.0 - 0.22) * (1 - surfaceData.metallic); output.ambientOcclusion = surfaceData.ambientOcclusion; output.specularOcclusion = surfaceData.specularOcclusion; output.perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness);\ output.subsurfaceColor = surfaceData.subsurfaceColor.rgb * surfaceData.subsurfaceColor.a; output.normalWS = surfaceData.normalWS; output.geomNormalWS = surfaceData.geomNormalWS; output.tangentWS = surfaceData.tangentWS; output.bitangentWS = normalize(cross(surfaceData.normalWS, surfaceData.tangentWS)); output.anisotropy = surfaceData.anisotropy; ConvertAnisotropyToRoughness(output.perceptualRoughness, surfaceData.anisotropy, output.roughnessT, output.roughnessB); return output; } PreLightData GetPreLightData_UTS(float3 V, PositionInputs posInput, inout UtsBSDFData bsdfData) { PreLightData preLightData; ZERO_INITIALIZE(PreLightData, preLightData); float3 N = bsdfData.normalWS; preLightData.NdotV = dot(N, V); preLightData.iblPerceptualRoughness = bsdfData.perceptualRoughness; float clampedNdotV = ClampNdotV(preLightData.NdotV); // Handle IBL + area light + multiscattering. // Note: use the not modified by anisotropy iblPerceptualRoughness here. float specularReflectivity = 1.0; #if _PBR_MODE_OFF preLightData.diffuseFGD = 1.0; preLightData.specularFGD = 1.0; #else GetPreIntegratedFGDGGXAndDisneyDiffuse(clampedNdotV, preLightData.iblPerceptualRoughness, bsdfData.fresnel0, bsdfData.fresnel90, preLightData.specularFGD, preLightData.diffuseFGD, specularReflectivity); #endif #ifdef LIT_USE_GGX_ENERGY_COMPENSATION // Ref: Practical multiple scattering compensation for microfacet models. // We only apply the formulation for metals. // For dielectrics, the change of reflectance is negligible. // We deem the intensity difference of a couple of percent for high values of roughness // to not be worth the cost of another precomputed table. // Note: this formulation bakes the BSDF non-symmetric! preLightData.energyCompensation = 1.0 / specularReflectivity - 1.0; #else preLightData.energyCompensation = 0.0; #endif // LIT_USE_GGX_ENERGY_COMPENSATION float3 iblN; #if _PBR_MODE_ANISOTROPY float TdotV = dot(bsdfData.tangentWS, V); float BdotV = dot(bsdfData.bitangentWS, V); preLightData.partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, clampedNdotV, bsdfData.roughnessT, bsdfData.roughnessB); // perceptualRoughness is use as input and output here GetGGXAnisotropicModifiedNormalAndRoughness(bsdfData.bitangentWS, bsdfData.tangentWS, N, V, bsdfData.anisotropy, preLightData.iblPerceptualRoughness, iblN, preLightData.iblPerceptualRoughness); #else preLightData.partLambdaV = GetSmithJointGGXPartLambdaV(clampedNdotV, bsdfData.roughnessT); iblN = N; #endif preLightData.iblR = reflect(-V, iblN); // Area light #ifdef USE_DIFFUSE_LAMBERT_BRDF preLightData.ltcTransformDiffuse = k_identity3x3; if (HasFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_SSS_DIFFUSE_POWER)) ModifyLambertLTCTransformForDiffusePower(preLightData.ltcTransformDiffuse, GetDiffusePower(bsdfData.diffusionProfileIndex)); #else preLightData.ltcTransformDiffuse = SampleLtcMatrix(bsdfData.perceptualRoughness, clampedNdotV, LTCLIGHTINGMODEL_DISNEY_DIFFUSE); #endif float perceptualRoughnessA = bsdfData.perceptualRoughness; preLightData.ltcTransformSpecular[0] = SampleLtcMatrix(perceptualRoughnessA, clampedNdotV, LTCLIGHTINGMODEL_GGX); // Construct a right-handed view-dependent orthogonal basis around the normal preLightData.orthoBasisViewNormal = GetOrthoBasisViewNormal(V, N, preLightData.NdotV); return preLightData; } void UtsClampRoughness(inout PreLightData preLightData, inout UtsBSDFData bsdfData, float minRoughness) { bsdfData.roughnessT = max(minRoughness, bsdfData.roughnessT); bsdfData.roughnessB = max(minRoughness, bsdfData.roughnessB); } // 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 #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; } 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