472 lines
19 KiB
Plaintext
472 lines
19 KiB
Plaintext
Shader "GAME/PickableHighlight"
|
|
{
|
|
Properties
|
|
{
|
|
[Header(Surface)][Space]
|
|
[MainColor] _BaseColor("Base Color", Color) = (1,1,1,1)
|
|
[MainTexture] _BaseMap("Base Map", 2D) = "white" {}
|
|
|
|
[Toggle(_NORMALMAP)] _UseNormalMap("Use Normal Map", Float) = 0
|
|
[Normal] _BumpMap("Normal Map", 2D) = "bump" {}
|
|
_NormalStrength("Normal Strength", Range(0,2)) = 1
|
|
|
|
[Toggle(_MASKMAP)] _UseMaskMap("Use Mask Map (R:Metallic G:AO A:Smooth)", Float) = 0
|
|
_MaskMap("Mask Map", 2D) = "white" {}
|
|
_Metallic("Metallic", Range(0,1)) = 0
|
|
_Smoothness("Smoothness", Range(0,1)) = 0.2
|
|
_Occlusion("Occlusion", Range(0,1)) = 1
|
|
|
|
_ShadowLift("Shadow Lift (lighten shadows so item never goes black)", Range(0,1)) = 0.25
|
|
|
|
[Header(Fresnel Rim silhouette pop)][Space]
|
|
[HDR] _RimColor("Rim Color", Color) = (1,0.85,0.35,1)
|
|
_RimPower("Rim Power (higher = thinner edge)", Range(0.5,12)) = 3
|
|
_RimIntensity("Rim Intensity", Range(0,8)) = 2.5
|
|
|
|
[Header(Shine Sweep moving highlight band)][Space]
|
|
[HDR] _ShineColor("Shine Color", Color) = (1,1,0.9,1)
|
|
_ShineDir("Shine Direction (object space xyz)", Vector) = (0,1,0,0)
|
|
_ShineTiling("Shine Tiling (bands across object)", Float) = 1.2
|
|
_ShineSpeed("Shine Speed", Float) = 0.6
|
|
_ShineSharpness("Shine Sharpness (higher = thinner band)", Range(1,64)) = 12
|
|
_ShineIntensity("Shine Intensity", Range(0,8)) = 2
|
|
|
|
[Header(Emissive Pulse gentle breathing)][Space]
|
|
_PulseSpeed("Pulse Speed", Float) = 2
|
|
_PulseMin("Pulse Min", Range(0,2)) = 0.6
|
|
_PulseMax("Pulse Max", Range(0,2)) = 1.1
|
|
|
|
[Header(Proximity Fade highlight reacts to player distance)][Space]
|
|
[Toggle(_DISTANCE_FADE)] _DistanceFade("Enable Distance Fade", Float) = 1
|
|
_FadeNear("Fade Near (full strength within, metres)", Float) = 3
|
|
_FadeFar("Fade Far (gone beyond, metres)", Float) = 8
|
|
|
|
[Header(Rendering)][Space]
|
|
[Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 2
|
|
}
|
|
|
|
SubShader
|
|
{
|
|
Tags
|
|
{
|
|
"RenderType" = "Opaque"
|
|
"RenderPipeline" = "UniversalPipeline"
|
|
"Queue" = "Geometry"
|
|
"UniversalMaterialType" = "Lit"
|
|
}
|
|
|
|
// Shared declarations for every pass.
|
|
HLSLINCLUDE
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
|
|
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
|
|
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
|
|
TEXTURE2D(_MaskMap); SAMPLER(sampler_MaskMap);
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
float4 _BaseMap_ST;
|
|
half4 _BaseColor;
|
|
half _NormalStrength;
|
|
half _Metallic;
|
|
half _Smoothness;
|
|
half _Occlusion;
|
|
half _ShadowLift;
|
|
half4 _RimColor;
|
|
half _RimPower;
|
|
half _RimIntensity;
|
|
half4 _ShineColor;
|
|
float4 _ShineDir;
|
|
float _ShineTiling;
|
|
float _ShineSpeed;
|
|
half _ShineSharpness;
|
|
half _ShineIntensity;
|
|
float _PulseSpeed;
|
|
half _PulseMin;
|
|
half _PulseMax;
|
|
float _FadeNear;
|
|
float _FadeFar;
|
|
CBUFFER_END
|
|
|
|
// =========================================================================
|
|
// Proximity strength: 1 when the camera is within _FadeNear, smoothly
|
|
// ramping down to 0 past _FadeFar. Camera-distance based, so it costs
|
|
// nothing on the CPU. Measured against the pixel world position so it
|
|
// stays correct under static batching (which flattens unity_ObjectToWorld).
|
|
// =========================================================================
|
|
half ProximityStrength(float3 positionWS)
|
|
{
|
|
#if defined(_DISTANCE_FADE)
|
|
float camDist = distance(_WorldSpaceCameraPos, positionWS);
|
|
return 1.0 - smoothstep(_FadeNear, _FadeFar, camDist);
|
|
#else
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
// =========================================================================
|
|
// Highlight emission: rim + animated sweep, scaled by the breathing pulse
|
|
// and by player proximity. This is what makes a pickable read in grass.
|
|
// =========================================================================
|
|
half3 ComputeHighlightEmission(float3 positionOS, half3 normalWS, half3 viewDirWS, float3 positionWS)
|
|
{
|
|
// Fresnel rim: bright on grazing angles so the silhouette detaches from grass.
|
|
half fresnel = pow(1.0 - saturate(dot(normalWS, viewDirWS)), _RimPower);
|
|
half3 rim = fresnel * _RimIntensity * _RimColor.rgb;
|
|
|
|
// Shine sweep: a band travelling along an object-space axis over time.
|
|
float coord = dot(positionOS, normalize(_ShineDir.xyz));
|
|
float phase = coord * _ShineTiling - _Time.y * _ShineSpeed;
|
|
half wave = sin(phase * 6.2831853) * 0.5 + 0.5;
|
|
half band = pow(wave, _ShineSharpness);
|
|
half3 shine = band * _ShineIntensity * _ShineColor.rgb;
|
|
|
|
// Breathing pulse so the item draws the eye without ever moving.
|
|
half pulse = lerp(_PulseMin, _PulseMax, sin(_Time.y * _PulseSpeed) * 0.5 + 0.5);
|
|
|
|
return (rim + shine) * pulse * ProximityStrength(positionWS);
|
|
}
|
|
ENDHLSL
|
|
|
|
// =====================================================================
|
|
// ForwardLit — full PBR (metallic/smoothness/normal/AO) + highlight.
|
|
// =====================================================================
|
|
Pass
|
|
{
|
|
Name "ForwardLit"
|
|
Tags { "LightMode" = "UniversalForward" }
|
|
|
|
Cull [_Cull]
|
|
ZWrite On
|
|
ZTest LEqual
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 3.0
|
|
#pragma vertex PickableVertex
|
|
#pragma fragment PickableFragment
|
|
|
|
#pragma shader_feature_local _NORMALMAP
|
|
#pragma shader_feature_local_fragment _MASKMAP
|
|
#pragma shader_feature_local_fragment _DISTANCE_FADE
|
|
|
|
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
|
|
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
|
|
#pragma multi_compile _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX
|
|
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
|
|
#pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
|
|
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
|
|
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING
|
|
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION
|
|
#pragma multi_compile _ _CLUSTER_LIGHT_LOOP
|
|
#pragma multi_compile _ LIGHTMAP_ON
|
|
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
|
|
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
|
|
#pragma multi_compile _ SHADOWS_SHADOWMASK
|
|
#pragma multi_compile_fog
|
|
#pragma multi_compile_instancing
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float4 tangentOS : TANGENT;
|
|
float2 uv : TEXCOORD0;
|
|
float2 lightmapUV : TEXCOORD1;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
float3 positionWS : TEXCOORD1;
|
|
float3 positionOS : TEXCOORD2;
|
|
half3 normalWS : TEXCOORD3;
|
|
half4 tangentWS : TEXCOORD4;
|
|
DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 5);
|
|
float fogFactor : TEXCOORD6;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
Varyings PickableVertex(Attributes IN)
|
|
{
|
|
Varyings OUT = (Varyings)0;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
|
|
|
VertexPositionInputs posInput = GetVertexPositionInputs(IN.positionOS.xyz);
|
|
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
|
|
|
|
OUT.positionCS = posInput.positionCS;
|
|
OUT.positionWS = posInput.positionWS;
|
|
OUT.positionOS = IN.positionOS.xyz;
|
|
OUT.normalWS = normalInput.normalWS;
|
|
real sign = IN.tangentOS.w * GetOddNegativeScale();
|
|
OUT.tangentWS = half4(normalInput.tangentWS, sign);
|
|
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
|
|
OUT.fogFactor = ComputeFogFactor(posInput.positionCS.z);
|
|
|
|
OUTPUT_LIGHTMAP_UV(IN.lightmapUV, unity_LightmapST, OUT.lightmapUV);
|
|
OUTPUT_SH(OUT.normalWS, OUT.vertexSH);
|
|
return OUT;
|
|
}
|
|
|
|
half4 PickableFragment(Varyings IN) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
half3 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv).rgb * _BaseColor.rgb;
|
|
|
|
// Mask map: R metallic, G occlusion, A smoothness.
|
|
half metallic = _Metallic;
|
|
half smoothness = _Smoothness;
|
|
half occlusion = _Occlusion;
|
|
#ifdef _MASKMAP
|
|
half4 mask = SAMPLE_TEXTURE2D(_MaskMap, sampler_MaskMap, IN.uv);
|
|
metallic *= mask.r;
|
|
occlusion *= mask.g;
|
|
smoothness *= mask.a;
|
|
#endif
|
|
|
|
// Normal mapping (TBN) when a normal map is supplied.
|
|
half3 normalWS = normalize(IN.normalWS);
|
|
half3 normalTS = half3(0, 0, 1);
|
|
#ifdef _NORMALMAP
|
|
normalTS = UnpackNormalScale(
|
|
SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, IN.uv), _NormalStrength);
|
|
float sgn = IN.tangentWS.w;
|
|
float3 bitangent = sgn * cross(normalWS, IN.tangentWS.xyz);
|
|
half3x3 tbn = half3x3(IN.tangentWS.xyz, bitangent, normalWS);
|
|
normalWS = normalize(TransformTangentToWorld(normalTS, tbn));
|
|
#endif
|
|
|
|
InputData inputData = (InputData)0;
|
|
inputData.positionWS = IN.positionWS;
|
|
inputData.normalWS = normalWS;
|
|
inputData.viewDirectionWS = normalize(GetWorldSpaceViewDir(IN.positionWS));
|
|
inputData.shadowCoord = TransformWorldToShadowCoord(IN.positionWS);
|
|
inputData.fogCoord = IN.fogFactor;
|
|
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.vertexSH, normalWS);
|
|
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.positionCS);
|
|
inputData.shadowMask = SAMPLE_SHADOWMASK(IN.lightmapUV);
|
|
|
|
SurfaceData surfaceData = (SurfaceData)0;
|
|
surfaceData.albedo = albedo;
|
|
surfaceData.metallic = metallic;
|
|
surfaceData.smoothness = smoothness;
|
|
surfaceData.occlusion = occlusion;
|
|
surfaceData.normalTS = normalTS;
|
|
surfaceData.alpha = 1.0;
|
|
// Highlight rides in the emission channel so PBR lighting stays correct.
|
|
surfaceData.emission = ComputeHighlightEmission(
|
|
IN.positionOS, normalWS, inputData.viewDirectionWS, IN.positionWS);
|
|
|
|
half4 color = UniversalFragmentPBR(inputData, surfaceData);
|
|
|
|
// Shadow lift: keep the item readable in deep shade instead of going black.
|
|
color.rgb = max(color.rgb, albedo * _ShadowLift);
|
|
|
|
color.rgb = MixFog(color.rgb, inputData.fogCoord);
|
|
color.a = 1.0;
|
|
return color;
|
|
}
|
|
ENDHLSL
|
|
}
|
|
|
|
// =====================================================================
|
|
// ShadowCaster — lets pickables cast shadows into the scene.
|
|
// =====================================================================
|
|
Pass
|
|
{
|
|
Name "ShadowCaster"
|
|
Tags { "LightMode" = "ShadowCaster" }
|
|
|
|
ZWrite On
|
|
ZTest LEqual
|
|
ColorMask 0
|
|
Cull [_Cull]
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 3.0
|
|
#pragma vertex ShadowVertex
|
|
#pragma fragment ShadowFragment
|
|
#pragma multi_compile_instancing
|
|
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
|
|
|
|
float3 _LightDirection;
|
|
float3 _LightPosition;
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
float4 GetShadowPositionHClip(Attributes IN)
|
|
{
|
|
float3 positionWS = TransformObjectToWorld(IN.positionOS.xyz);
|
|
float3 normalWS = TransformObjectToWorldNormal(IN.normalOS);
|
|
|
|
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
|
|
float3 lightDirectionWS = normalize(_LightPosition - positionWS);
|
|
#else
|
|
float3 lightDirectionWS = _LightDirection;
|
|
#endif
|
|
|
|
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
|
|
positionCS = ApplyShadowClamping(positionCS);
|
|
return positionCS;
|
|
}
|
|
|
|
Varyings ShadowVertex(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
OUT.positionCS = GetShadowPositionHClip(IN);
|
|
return OUT;
|
|
}
|
|
|
|
half4 ShadowFragment(Varyings IN) : SV_Target
|
|
{
|
|
return 0;
|
|
}
|
|
ENDHLSL
|
|
}
|
|
|
|
// =====================================================================
|
|
// DepthOnly — feeds the depth prepass.
|
|
// =====================================================================
|
|
Pass
|
|
{
|
|
Name "DepthOnly"
|
|
Tags { "LightMode" = "DepthOnly" }
|
|
|
|
ZWrite On
|
|
ColorMask R
|
|
Cull [_Cull]
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 3.0
|
|
#pragma vertex DepthVertex
|
|
#pragma fragment DepthFragment
|
|
#pragma multi_compile_instancing
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
Varyings DepthVertex(Attributes IN)
|
|
{
|
|
Varyings OUT;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
|
|
return OUT;
|
|
}
|
|
|
|
half4 DepthFragment(Varyings IN) : SV_Target
|
|
{
|
|
return 0;
|
|
}
|
|
ENDHLSL
|
|
}
|
|
|
|
// =====================================================================
|
|
// DepthNormals — supplies surface normals for SSAO / depth-normal effects.
|
|
// =====================================================================
|
|
Pass
|
|
{
|
|
Name "DepthNormals"
|
|
Tags { "LightMode" = "DepthNormals" }
|
|
|
|
ZWrite On
|
|
Cull [_Cull]
|
|
|
|
HLSLPROGRAM
|
|
#pragma target 3.0
|
|
#pragma vertex DepthNormalsVertex
|
|
#pragma fragment DepthNormalsFragment
|
|
#pragma shader_feature_local _NORMALMAP
|
|
#pragma multi_compile_instancing
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
|
|
|
|
struct Attributes
|
|
{
|
|
float4 positionOS : POSITION;
|
|
float3 normalOS : NORMAL;
|
|
float4 tangentOS : TANGENT;
|
|
float2 uv : TEXCOORD0;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct Varyings
|
|
{
|
|
float4 positionCS : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
half3 normalWS : TEXCOORD1;
|
|
half4 tangentWS : TEXCOORD2;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
Varyings DepthNormalsVertex(Attributes IN)
|
|
{
|
|
Varyings OUT = (Varyings)0;
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
|
|
|
OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
|
|
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
|
|
VertexNormalInputs normalInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
|
|
OUT.normalWS = normalInput.normalWS;
|
|
real sign = IN.tangentOS.w * GetOddNegativeScale();
|
|
OUT.tangentWS = half4(normalInput.tangentWS, sign);
|
|
return OUT;
|
|
}
|
|
|
|
half4 DepthNormalsFragment(Varyings IN) : SV_Target
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN);
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
|
|
|
|
half3 normalWS = normalize(IN.normalWS);
|
|
#ifdef _NORMALMAP
|
|
half3 normalTS = UnpackNormalScale(
|
|
SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, IN.uv), _NormalStrength);
|
|
float sgn = IN.tangentWS.w;
|
|
float3 bitangent = sgn * cross(normalWS, IN.tangentWS.xyz);
|
|
half3x3 tbn = half3x3(IN.tangentWS.xyz, bitangent, normalWS);
|
|
normalWS = normalize(TransformTangentToWorld(normalTS, tbn));
|
|
#endif
|
|
return half4(NormalizeNormalPerPixel(normalWS), 0.0);
|
|
}
|
|
ENDHLSL
|
|
}
|
|
}
|
|
|
|
FallBack "Universal Render Pipeline/Lit"
|
|
}
|