2021-09-09 20:42:29 -04:00

310 lines
13 KiB
HLSL

//-------------------------------------------------------------------------------------
// Defines
//-------------------------------------------------------------------------------------
// Use surface gradient normal mapping as it handle correctly triplanar normal mapping and multiple UVSet
#ifndef SHADER_STAGE_RAY_TRACING
#define SURFACE_GRADIENT
#endif
//-------------------------------------------------------------------------------------
// Fill SurfaceData/Builtin data function
//-------------------------------------------------------------------------------------
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/SampleUVMapping.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/MaterialUtilities.hlsl"
#ifndef SHADER_STAGE_RAY_TRACING
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalUtilities.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDecalData.hlsl"
#endif
//#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/SphericalCapPivot/SPTDistribution.hlsl"
//#define SPECULAR_OCCLUSION_USE_SPTD
// Struct that gather UVMapping info of all layers + common calculation
// This is use to abstract the mapping that can differ on layers
struct LayerTexCoord
{
#ifndef LAYERED_LIT_SHADER
UVMapping base;
UVMapping details;
#else
// Regular texcoord
UVMapping base0;
UVMapping base1;
UVMapping base2;
UVMapping base3;
UVMapping details0;
UVMapping details1;
UVMapping details2;
UVMapping details3;
// Dedicated for blend mask
UVMapping blendMask;
#endif
// Store information that will be share by all UVMapping
float3 vertexNormalWS; // TODO: store also object normal map for object triplanar
float3 triplanarWeights;
#ifdef SURFACE_GRADIENT
// tangent basis for each UVSet - up to 4 for now
float3 vertexTangentWS0, vertexBitangentWS0;
float3 vertexTangentWS1, vertexBitangentWS1;
float3 vertexTangentWS2, vertexBitangentWS2;
float3 vertexTangentWS3, vertexBitangentWS3;
#endif
};
#ifdef SURFACE_GRADIENT
void GenerateLayerTexCoordBasisTB(FragInputs input, inout LayerTexCoord layerTexCoord)
{
float3 vertexNormalWS = input.tangentToWorld[2];
layerTexCoord.vertexTangentWS0 = input.tangentToWorld[0];
layerTexCoord.vertexBitangentWS0 = input.tangentToWorld[1];
float3 dPdx = ddx_fine(input.positionRWS);
float3 dPdy = ddy_fine(input.positionRWS);
float3 sigmaX = dPdx - dot(dPdx, vertexNormalWS) * vertexNormalWS;
float3 sigmaY = dPdy - dot(dPdy, vertexNormalWS) * vertexNormalWS;
//float flipSign = dot(sigmaY, cross(vertexNormalWS, sigmaX) ) ? -1.0 : 1.0;
float flipSign = dot(dPdy, cross(vertexNormalWS, dPdx)) < 0.0 ? -1.0 : 1.0; // gives same as the commented out line above
// TODO: Optimize! The compiler will not be able to remove the tangent space that are not use because it can't know due to our UVMapping constant we use for both base and details
// To solve this we should track which UVSet is use for normal mapping... Maybe not as simple as it sounds
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord1.xy, layerTexCoord.vertexTangentWS1, layerTexCoord.vertexBitangentWS1);
#if defined(_REQUIRE_UV2) || defined(_REQUIRE_UV3)
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord2.xy, layerTexCoord.vertexTangentWS2, layerTexCoord.vertexBitangentWS2);
#endif
#if defined(_REQUIRE_UV3)
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord3.xy, layerTexCoord.vertexTangentWS3, layerTexCoord.vertexBitangentWS3);
#endif
}
#endif
#ifndef LAYERED_LIT_SHADER
// Want to use only one sampler for normalmap/bentnormalmap either we use OS or TS. And either we have normal map or bent normal or both.
#ifdef _NORMALMAP_TANGENT_SPACE
#if defined(_NORMALMAP)
#define SAMPLER_NORMALMAP_IDX sampler_NormalMap
#elif defined(_BENTNORMALMAP)
#define SAMPLER_NORMALMAP_IDX sampler_BentNormalMap
#endif
#else
#if defined(_NORMALMAP)
#define SAMPLER_NORMALMAP_IDX sampler_NormalMapOS
#elif defined(_BENTNORMALMAP)
#define SAMPLER_NORMALMAP_IDX sampler_BentNormalMapOS
#endif
#endif
#define SAMPLER_DETAILMAP_IDX sampler_DetailMap
#define SAMPLER_MASKMAP_IDX sampler_MaskMap
#define SAMPLER_HEIGHTMAP_IDX sampler_HeightMap
#define SAMPLER_SUBSURFACE_MASK_MAP_IDX sampler_SubsurfaceMaskMap
#define SAMPLER_THICKNESSMAP_IDX sampler_ThicknessMap
// include LitDataIndividualLayer to define GetSurfaceData
#define LAYER_INDEX 0
#define ADD_IDX(Name) Name
#define ADD_ZERO_IDX(Name) Name
#ifdef _NORMALMAP
#define _NORMALMAP_IDX
#endif
#ifdef _NORMALMAP_TANGENT_SPACE
#define _NORMALMAP_TANGENT_SPACE_IDX
#endif
#ifdef _DETAIL_MAP
#define _DETAIL_MAP_IDX
#endif
#ifdef _SUBSURFACE_MASK_MAP
#define _SUBSURFACE_MASK_MAP_IDX
#endif
#ifdef _THICKNESSMAP
#define _THICKNESSMAP_IDX
#endif
#ifdef _MASKMAP
#define _MASKMAP_IDX
#endif
#ifdef _BENTNORMALMAP
#define _BENTNORMALMAP_IDX
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataIndividualLayer.hlsl"
// This maybe call directly by tessellation (domain) shader, thus all part regarding surface gradient must be done
// in function with FragInputs input as parameters
// layerTexCoord must have been initialize to 0 outside of this function
void GetLayerTexCoord(float2 texCoord0, float2 texCoord1, float2 texCoord2, float2 texCoord3,
float3 positionRWS, float3 vertexNormalWS, inout LayerTexCoord layerTexCoord)
{
layerTexCoord.vertexNormalWS = vertexNormalWS;
layerTexCoord.triplanarWeights = ComputeTriplanarWeights(vertexNormalWS);
int mappingType = UV_MAPPING_UVSET;
#if defined(_MAPPING_PLANAR)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_MAPPING_TRIPLANAR)
mappingType = UV_MAPPING_TRIPLANAR;
#endif
// Be sure that the compiler is aware that we don't use UV1 to UV3 for main layer so it can optimize code
ComputeLayerTexCoord( texCoord0, texCoord1, texCoord2, texCoord3, _UVMappingMask, _UVDetailsMappingMask,
_BaseColorMap_ST.xy, _BaseColorMap_ST.zw, _DetailMap_ST.xy, _DetailMap_ST.zw, 1.0, _LinkDetailsWithBase,
positionRWS, _TexWorldScale,
mappingType, layerTexCoord);
}
// This is call only in this file
// layerTexCoord must have been initialize to 0 outside of this function
void GetLayerTexCoord(FragInputs input, inout LayerTexCoord layerTexCoord)
{
#ifdef SURFACE_GRADIENT
GenerateLayerTexCoordBasisTB(input, layerTexCoord);
#endif
GetLayerTexCoord( input.texCoord0.xy, input.texCoord1.xy, input.texCoord2.xy, input.texCoord3.xy,
input.positionRWS, input.tangentToWorld[2].xyz, layerTexCoord);
}
#if !defined(SHADER_STAGE_RAY_TRACING)
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataDisplacement.hlsl"
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitBuiltinData.hlsl"
void GetSurfaceAndBuiltinData(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
#ifdef _DOUBLESIDED_ON
float3 doubleSidedConstants = _DoubleSidedConstants.xyz;
#else
float3 doubleSidedConstants = float3(1.0, 1.0, 1.0);
#endif
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 alphaValue = SAMPLE_UVMAPPING_TEXTURE2D(_BaseColorMap, sampler_BaseColorMap, layerTexCoord.base).a * _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
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 = GetSurfaceData(input, layerTexCoord, surfaceData, normalTS, bentNormalTS);
GetNormalWS(input, normalTS, surfaceData.normalWS, doubleSidedConstants);
surfaceData.geomNormalWS = input.tangentToWorld[2];
surfaceData.specularOcclusion = 1.0; // This need to be init here to quiet the compiler in case of decal, but can be override later.
#if HAVE_DECALS
if (_EnableDecals)
{
// Both uses and modifies 'surfaceData.normalWS'.
DecalSurfaceData decalSurfaceData = GetDecalSurfaceData(posInput, input, alpha);
ApplyDecalToSurfaceData(decalSurfaceData, input.tangentToWorld[2], surfaceData);
}
#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) && !defined(SHADER_STAGE_RAY_TRACING)
if (_DebugMipMapMode != DEBUGMIPMAPMODE_NONE)
{
surfaceData.baseColor = GetTextureDataDebug(_DebugMipMapMode, layerTexCoord.base.uv, _BaseColorMap, _BaseColorMap_TexelSize, _BaseColorMap_MipInfo, surfaceData.baseColor);
surfaceData.metallic = 0;
}
// We need to call ApplyDebugToSurfaceData after filling the surfarcedata 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(_BENTNORMALMAP) && defined(_SPECULAR_OCCLUSION_FROM_BENT_NORMAL_MAP)
// If we have bent normal and ambient occlusion, process a specular occlusion
#ifdef SPECULAR_OCCLUSION_USE_SPTD
surfaceData.specularOcclusion = GetSpecularOcclusionFromBentAOPivot(V, bentNormalWS, surfaceData.normalWS, surfaceData.ambientOcclusion, PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness));
#else
surfaceData.specularOcclusion = GetSpecularOcclusionFromBentAO(V, bentNormalWS, surfaceData.normalWS, surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness));
#endif
// 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
surfaceData.perceptualSmoothness = GeometricNormalFiltering(surfaceData.perceptualSmoothness, input.tangentToWorld[2], _SpecularAAScreenSpaceVariance, _SpecularAAThreshold);
#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
}
#if !defined(SHADER_STAGE_RAY_TRACING)
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitDataMeshModification.hlsl"
#endif
#endif // #ifndef LAYERED_LIT_SHADER