#ifndef UTS_LIT_DATA #define UTS_LIT_DATA float UtsGetSurfaceData(FragInputs input, LayerTexCoord layerTexCoord, out SurfaceData surfaceData, out float3 normalTS, out float3 bentNormalTS) { float3 detailNormalTS = float3(0.0, 0.0, 0.0); float detailMask = 0.0; #ifdef _DETAIL_MAP_IDX detailMask = 1.0; #ifdef _MASKMAP_IDX detailMask = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).b; #endif float2 detailAlbedoAndSmoothness = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details)).rb; float detailAlbedo = detailAlbedoAndSmoothness.r * 2.0 - 1.0; float detailSmoothness = detailAlbedoAndSmoothness.g * 2.0 - 1.0; // Resample the detail map but this time for the normal map. This call should be optimize by the compiler // We split both call due to trilinear mapping detailNormalTS = SAMPLE_UVMAPPING_NORMALMAP_AG(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details), ADD_IDX(_DetailNormalScale)); #endif float4 color = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_BaseColorMap), ADD_ZERO_IDX(sampler_BaseColorMap), ADD_IDX(layerTexCoord.base)).rgba * ADD_IDX(_BaseColor).rgba; surfaceData.baseColor = color.rgb; float alpha = 1.0f; #ifdef DEBUG_DISPLAY if (_DebugMipMapMode == DEBUGMIPMAPMODE_NONE) #endif { alpha = color.a; alpha = lerp(ADD_IDX(_AlphaRemapMin), ADD_IDX(_AlphaRemapMax), alpha); } #ifdef _DETAIL_MAP_IDX // Goal: we want the detail albedo map to be able to darken down to black and brighten up to white the surface albedo. // The scale control the speed of the gradient. We simply remap detailAlbedo from [0..1] to [-1..1] then perform a lerp to black or white // with a factor based on speed. // For base color we interpolate in sRGB space (approximate here as square) as it get a nicer perceptual gradient float albedoDetailSpeed = saturate(abs(detailAlbedo) * ADD_IDX(_DetailAlbedoScale)); float3 baseColorOverlay = lerp(sqrt(surfaceData.baseColor), (detailAlbedo < 0.0) ? float3(0.0, 0.0, 0.0) : float3(1.0, 1.0, 1.0), albedoDetailSpeed * albedoDetailSpeed); baseColorOverlay *= baseColorOverlay; // Lerp with details mask surfaceData.baseColor = lerp(surfaceData.baseColor, saturate(baseColorOverlay), detailMask); #endif surfaceData.specularOcclusion = 1.0; // Will be setup outside of this function surfaceData.normalWS = float3(0.0, 0.0, 0.0); // Need to init this to keep quiet the compiler, but this is overriden later (0, 0, 0) so if we forget to override the compiler may comply. surfaceData.geomNormalWS = float3(0.0, 0.0, 0.0); // Not used, just to keep compiler quiet. normalTS = ADD_IDX(GetNormalTS)(input, layerTexCoord, detailNormalTS, detailMask); bentNormalTS = ADD_IDX(GetBentNormalTS)(input, layerTexCoord, normalTS, detailNormalTS, detailMask); #if _PBR_MODE_OFF surfaceData.perceptualSmoothness = 0.0; #else #if defined(_MASKMAP_IDX) surfaceData.perceptualSmoothness = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).a; surfaceData.perceptualSmoothness = lerp(ADD_IDX(_SmoothnessRemapMin), ADD_IDX(_SmoothnessRemapMax), surfaceData.perceptualSmoothness); #else surfaceData.perceptualSmoothness = ADD_IDX(_Smoothness); #endif #endif #ifdef _DETAIL_MAP_IDX // See comment for baseColorOverlay float smoothnessDetailSpeed = saturate(abs(detailSmoothness) * ADD_IDX(_DetailSmoothnessScale)); float smoothnessOverlay = lerp(surfaceData.perceptualSmoothness, (detailSmoothness < 0.0) ? 0.0 : 1.0, smoothnessDetailSpeed); // Lerp with details mask surfaceData.perceptualSmoothness = lerp(surfaceData.perceptualSmoothness, saturate(smoothnessOverlay), detailMask); #endif #if _PBR_MODE_OFF surfaceData.metallic = 0.0; surfaceData.ambientOcclusion = 1.0; #else // MaskMap is RGBA: Metallic, Ambient Occlusion (Optional), detail Mask (Optional), Smoothness #ifdef _MASKMAP_IDX surfaceData.metallic = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).r; surfaceData.metallic = lerp(ADD_IDX(_MetallicRemapMin), ADD_IDX(_MetallicRemapMax), surfaceData.metallic); surfaceData.ambientOcclusion = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).g; surfaceData.ambientOcclusion = lerp(ADD_IDX(_AORemapMin), ADD_IDX(_AORemapMax), surfaceData.ambientOcclusion); #else surfaceData.metallic = ADD_IDX(_Metallic); surfaceData.ambientOcclusion = 1.0; #endif #endif surfaceData.diffusionProfileHash = asuint(ADD_IDX(_DiffusionProfileHash)); surfaceData.subsurfaceMask = ADD_IDX(_SubsurfaceMask); surfaceData.transmissionMask = ADD_IDX(_TransmissionMask); #ifdef _SUBSURFACE_MASK_MAP_IDX surfaceData.subsurfaceMask *= SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_SubsurfaceMaskMap), SAMPLER_SUBSURFACE_MASK_MAP_IDX, ADD_IDX(layerTexCoord.base)).r; #endif #ifdef _TRANSMISSION_MASK_MAP_IDX surfaceData.transmissionMask *= SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_TransmissionMaskMap), SAMPLER_TRANSMISSION_MASK_MAP_IDX, ADD_IDX(layerTexCoord.base)).r; #endif #ifdef _THICKNESSMAP_IDX surfaceData.thickness = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_ThicknessMap), SAMPLER_THICKNESSMAP_IDX, ADD_IDX(layerTexCoord.base)).r; surfaceData.thickness = ADD_IDX(_ThicknessRemap).x + ADD_IDX(_ThicknessRemap).y * surfaceData.thickness; #else surfaceData.thickness = ADD_IDX(_Thickness); #endif // This part of the code is not used in case of layered shader but we keep the same macro system for simplicity #if !defined(LAYERED_LIT_SHADER) // These static material feature allow compile time optimization surfaceData.materialFeatures = MATERIALFEATUREFLAGS_LIT_STANDARD; #ifdef _MATERIAL_FEATURE_SUBSURFACE_SCATTERING surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SUBSURFACE_SCATTERING; #endif #ifdef _MATERIAL_FEATURE_TRANSMISSION surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_TRANSMISSION; #endif #ifdef _MATERIAL_FEATURE_ANISOTROPY surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_ANISOTROPY; #endif #ifdef _MATERIAL_FEATURE_CLEAR_COAT surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_CLEAR_COAT; #endif #ifdef _MATERIAL_FEATURE_IRIDESCENCE surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_IRIDESCENCE; #endif #ifdef _MATERIAL_FEATURE_SPECULAR_COLOR surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_LIT_SPECULAR_COLOR; #endif #ifdef _TANGENTMAP #ifdef _NORMALMAP_TANGENT_SPACE_IDX // Normal and tangent use same space // Tangent space vectors always use only 2 channels. float3 tangentTS = UnpackNormalmapRGorAG(SAMPLE_UVMAPPING_TEXTURE2D(_TangentMap, sampler_TangentMap, layerTexCoord.base), 1.0); surfaceData.tangentWS = TransformTangentToWorld(tangentTS, input.tangentToWorld); #else // Object space // Note: There is no such a thing like triplanar with object space normal, so we call directly 2D function float3 tangentOS = UnpackNormalRGB(SAMPLE_TEXTURE2D(_TangentMapOS, sampler_TangentMapOS, layerTexCoord.base.uv), 1.0); surfaceData.tangentWS = TransformObjectToWorldNormal(tangentOS); #endif #else // Note we don't normalize tangentWS either with a tangentmap above or using the interpolated tangent from the TBN frame // as it will be normalized later with a call to Orthonormalize(): surfaceData.tangentWS = input.tangentToWorld[0].xyz; // The tangent is not normalize in tangentToWorld for mikkt. TODO: Check if it expected that we normalize with Morten. Tag: SURFACE_GRADIENT #endif #ifdef _ANISOTROPYMAP surfaceData.anisotropy = SAMPLE_UVMAPPING_TEXTURE2D(_AnisotropyMap, sampler_AnisotropyMap, layerTexCoord.base).r; #else surfaceData.anisotropy = 1.0; #endif surfaceData.anisotropy *= ADD_IDX(_Anisotropy); surfaceData.specularColor = _SpecularColor.rgb; #ifdef _SPECULARCOLORMAP surfaceData.specularColor *= SAMPLE_UVMAPPING_TEXTURE2D(_SpecularColorMap, sampler_SpecularColorMap, layerTexCoord.base).rgb; #endif #ifdef _MATERIAL_FEATURE_SPECULAR_COLOR // Require to have setup baseColor // Reproduce the energy conservation done in legacy Unity. Not ideal but better for compatibility and users can unchek it surfaceData.baseColor *= _EnergyConservingSpecularColor > 0.0 ? (1.0 - Max3(surfaceData.specularColor.r, surfaceData.specularColor.g, surfaceData.specularColor.b)) : 1.0; #endif #if HAS_REFRACTION if (_EnableSSRefraction) { surfaceData.ior = _Ior; surfaceData.transmittanceColor = _TransmittanceColor; #ifdef _TRANSMITTANCECOLORMAP surfaceData.transmittanceColor *= SAMPLE_UVMAPPING_TEXTURE2D(_TransmittanceColorMap, sampler_TransmittanceColorMap, ADD_IDX(layerTexCoord.base)).rgb; #endif surfaceData.atDistance = _ATDistance; // Rough refraction don't use opacity. Instead we use opacity as a transmittance mask. surfaceData.transmittanceMask = (1.0 - alpha); alpha = 1.0; } else { surfaceData.ior = 1.0; surfaceData.transmittanceColor = float3(1.0, 1.0, 1.0); surfaceData.atDistance = 1.0; surfaceData.transmittanceMask = 0.0; alpha = 1.0; } #else surfaceData.ior = 1.0; surfaceData.transmittanceColor = float3(1.0, 1.0, 1.0); surfaceData.atDistance = 1.0; surfaceData.transmittanceMask = 0.0; #endif #ifdef _MATERIAL_FEATURE_CLEAR_COAT surfaceData.coatMask = _CoatMask; // To shader feature for keyword to limit the variant surfaceData.coatMask *= SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_CoatMaskMap), ADD_ZERO_IDX(sampler_CoatMaskMap), ADD_IDX(layerTexCoord.base)).r; #else surfaceData.coatMask = 0.0; #endif #ifdef _MATERIAL_FEATURE_IRIDESCENCE #ifdef _IRIDESCENCE_THICKNESSMAP surfaceData.iridescenceThickness = SAMPLE_UVMAPPING_TEXTURE2D(_IridescenceThicknessMap, sampler_IridescenceThicknessMap, layerTexCoord.base).r; surfaceData.iridescenceThickness = _IridescenceThicknessRemap.x + _IridescenceThicknessRemap.y * surfaceData.iridescenceThickness; #else surfaceData.iridescenceThickness = _IridescenceThickness; #endif surfaceData.iridescenceMask = _IridescenceMask; surfaceData.iridescenceMask *= SAMPLE_UVMAPPING_TEXTURE2D(_IridescenceMaskMap, sampler_IridescenceMaskMap, layerTexCoord.base).r; #else surfaceData.iridescenceThickness = 0.0; surfaceData.iridescenceMask = 0.0; #endif #else // #if !defined(LAYERED_LIT_SHADER) // Mandatory to setup value to keep compiler quiet // Layered shader material feature are define outside of this call surfaceData.materialFeatures = 0; // All these parameters are ignore as they are re-setup outside of the layers function // Note: any parameters set here must also be set in GetSurfaceAndBuiltinData() layer version surfaceData.tangentWS = float3(0.0, 0.0, 0.0); surfaceData.anisotropy = 0.0; surfaceData.specularColor = float3(0.0, 0.0, 0.0); surfaceData.iridescenceThickness = 0.0; surfaceData.iridescenceMask = 0.0; surfaceData.coatMask = 0.0; // Transparency surfaceData.ior = 1.0; surfaceData.transmittanceColor = float3(1.0, 1.0, 1.0); surfaceData.atDistance = 1000000.0; surfaceData.transmittanceMask = 0.0; #endif // #if !defined(LAYERED_LIT_SHADER) return alpha; } void UtsGetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs posInput, out SurfaceData surfaceData, out BuiltinData builtinData RAY_TRACING_OPTIONAL_PARAMETERS) { // Fix case 1210058. With Lit.shader / LayeredLit.shader we always have UV1. But in the case of some SpeedTree mesh, there is no stream sent // and UV1 is corrupt when we use surface gradient. In case UV1 aren't required we set them to 0, so we ensure there is no garbage. // When using lightmaps, the uv1 is always valid but we don't update _UVMappingMask.y to 1 // So when we are using them, we just need to keep the UVs as is. #if !defined(LIGHTMAP_ON) && defined(SURFACE_GRADIENT) input.texCoord1 = (_UVMappingMask.y + _UVDetailsMappingMask.y + _UVMappingMaskEmissive.y) > 0 ? input.texCoord1 : 0; #endif // Don't dither if displaced tessellation (we're fading out the displacement instead to match the next LOD) #if !defined(SHADER_STAGE_RAY_TRACING) && !defined(_TESSELLATION_DISPLACEMENT) #ifdef LOD_FADE_CROSSFADE // enable dithering LOD transition if user select CrossFade transition in LOD group LODDitheringTransition(ComputeFadeMaskSeed(V, posInput.positionSS), unity_LODFade.x); #endif #endif float3 doubleSidedConstants = GetDoubleSidedConstants(); ApplyDoubleSidedFlipOrMirror(input, doubleSidedConstants); // Apply double sided flip on the vertex normal LayerTexCoord layerTexCoord; ZERO_INITIALIZE(LayerTexCoord, layerTexCoord); GetLayerTexCoord(input, layerTexCoord); #if !defined(SHADER_STAGE_RAY_TRACING) float depthOffset = ApplyPerPixelDisplacement(input, V, layerTexCoord); #ifdef _DEPTHOFFSET_ON ApplyDepthOffsetPositionInput(V, depthOffset, GetViewForwardDir(), GetWorldToHClipMatrix(), posInput); #endif #else float depthOffset = 0.0; #endif #if defined(_ALPHATEST_ON) float alphaTex = SAMPLE_UVMAPPING_TEXTURE2D(_BaseColorMap, sampler_BaseColorMap, layerTexCoord.base).a; alphaTex = lerp(_AlphaRemapMin, _AlphaRemapMax, alphaTex); float alphaValue = alphaTex * _BaseColor.a; // Perform alha test very early to save performance (a killed pixel will not sample textures) #if SHADERPASS == SHADERPASS_TRANSPARENT_DEPTH_PREPASS float alphaCutoff = _AlphaCutoffPrepass; #elif SHADERPASS == SHADERPASS_TRANSPARENT_DEPTH_POSTPASS float alphaCutoff = _AlphaCutoffPostpass; #elif (SHADERPASS == SHADERPASS_SHADOWS) || (SHADERPASS == SHADERPASS_RAYTRACING_VISIBILITY) float alphaCutoff = _UseShadowThreshold ? _AlphaCutoffShadow : _AlphaCutoff; #else float alphaCutoff = _AlphaCutoff; #endif // clip(-0.1); GENERIC_ALPHA_TEST(alphaValue, alphaCutoff); #endif // We perform the conversion to world of the normalTS outside of the GetSurfaceData // so it allow us to correctly deal with detail normal map and optimize the code for the layered shaders float3 normalTS; float3 bentNormalTS; float3 bentNormalWS; float alpha = UtsGetSurfaceData(input, layerTexCoord, surfaceData, normalTS, bentNormalTS); // This need to be init here to quiet the compiler in case of decal, but can be override later. surfaceData.geomNormalWS = input.tangentToWorld[2]; surfaceData.specularOcclusion = 1.0; #ifdef DECAL_NORMAL_BLENDING if (_EnableDecals) { #ifndef SURFACE_GRADIENT normalTS = SurfaceGradientFromTangentSpaceNormalAndFromTBN(normalTS, input.tangentToWorld[0], input.tangentToWorld[1]); #endif DecalSurfaceData decalSurfaceData = GetDecalSurfaceData(posInput, input, alpha); ApplyDecalToSurfaceData(decalSurfaceData, input.tangentToWorld[2], surfaceData, normalTS); } GetNormalWS_SG(input, normalTS, surfaceData.normalWS, doubleSidedConstants); #else GetNormalWS(input, normalTS, surfaceData.normalWS, doubleSidedConstants); #if HAVE_DECALS if (_EnableDecals) { // Both uses and modifies 'surfaceData.normalWS'. DecalSurfaceData decalSurfaceData = GetDecalSurfaceData(posInput, input, alpha); ApplyDecalToSurfaceData(decalSurfaceData, input.tangentToWorld[2], surfaceData); } #endif #endif // Use bent normal to sample GI if available #ifdef _BENTNORMALMAP GetNormalWS(input, bentNormalTS, bentNormalWS, doubleSidedConstants); #else bentNormalWS = surfaceData.normalWS; #endif #if defined(DEBUG_DISPLAY) #if !defined(SHADER_STAGE_RAY_TRACING) // Mipmap mode debugging isn't supported with ray tracing as it relies on derivatives if (_DebugMipMapMode != DEBUGMIPMAPMODE_NONE) { surfaceData.baseColor = GET_TEXTURE_STREAMING_DEBUG(posInput.positionSS, input.texCoord0); surfaceData.metallic = 0; } #endif // We need to call ApplyDebugToSurfaceData after filling the surfaceData and before filling builtinData // as it can modify attribute use for static lighting ApplyDebugToSurfaceData(input.tangentToWorld, surfaceData); #endif // By default we use the ambient occlusion with Tri-ace trick (apply outside) for specular occlusion. // If user provide bent normal then we process a better term #if defined(_SPECULAR_OCCLUSION_FROM_BENT_NORMAL_MAP) // If we have bent normal and ambient occlusion, process a specular occlusion surfaceData.specularOcclusion = GetSpecularOcclusionFromBentAO(V, bentNormalWS, surfaceData.normalWS, surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness)); // Don't do spec occ from Ambient if there is no mask mask #elif defined(_MASKMAP) && !defined(_SPECULAR_OCCLUSION_NONE) surfaceData.specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(ClampNdotV(dot(surfaceData.normalWS, V)), surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness)); #endif // This is use with anisotropic material surfaceData.tangentWS = Orthonormalize(surfaceData.tangentWS, surfaceData.normalWS); #if defined(_ENABLE_GEOMETRIC_SPECULAR_AA) && !defined(SHADER_STAGE_RAY_TRACING) // Specular AA #ifdef PROJECTED_SPACE_NDF_FILTERING surfaceData.perceptualSmoothness = ProjectedSpaceGeometricNormalFiltering(surfaceData.perceptualSmoothness, input.tangentToWorld[2], _SpecularAAScreenSpaceVariance, _SpecularAAThreshold); #else surfaceData.perceptualSmoothness = GeometricNormalFiltering(surfaceData.perceptualSmoothness, input.tangentToWorld[2], _SpecularAAScreenSpaceVariance, _SpecularAAThreshold); #endif #endif // Caution: surfaceData must be fully initialize before calling GetBuiltinData GetBuiltinData(input, V, posInput, surfaceData, alpha, bentNormalWS, depthOffset, layerTexCoord.base, builtinData); #ifdef _ALPHATEST_ON // Used for sharpening by alpha to mask builtinData.alphaClipTreshold = alphaCutoff; #endif RAY_TRACING_OPTIONAL_ALPHA_TEST_PASS } #endif