From ac25f5923231565749067b29907d32b82246d413 Mon Sep 17 00:00:00 2001 From: MelekTaus Moribundus Date: Sun, 28 Jun 2026 17:18:32 +0200 Subject: [PATCH] Add radial hero-cutout shader for third-person camera Reveal the player when geometry sits between the orbit camera and the character: a screen-space circular mask in a URP/Lit clone (HeroCutoutLit) clips occluders in front of the player, depth-gated so only geometry nearer than the hero is cut. The cutout lives outside UnityPerMaterial (SRP batcher intact) and is a no-op when disarmed, so occluders look identical to URP/Lit. A runtime driver (HeroCutout.cs on Main/GameManager) feeds the player's screen position, radius, feather and depth into global shader properties and only arms while the third-person orbit vcam is live; it disarms in first-person, free-cam and the pause menu. Applied to the lobby walls via a dedicated occluder material (floor left solid). Shipped but shelved for now. Co-Authored-By: Claude Opus 4.8 --- Assets/Materials/Hero Cutout Occluder.mat | 123 ++++ .../Materials/Hero Cutout Occluder.mat.meta | 8 + Assets/Scenes/Lobby.unity | 14 +- Assets/Scenes/Main.unity | 19 + Assets/Scripts/HeroCutout.cs | 94 +++ Assets/Scripts/HeroCutout.cs.meta | 2 + Assets/Shaders/HeroCutout.hlsl | 46 ++ Assets/Shaders/HeroCutout.hlsl.meta | 7 + Assets/Shaders/HeroCutoutLit.shader | 581 ++++++++++++++++++ Assets/Shaders/HeroCutoutLit.shader.meta | 9 + 10 files changed, 896 insertions(+), 7 deletions(-) create mode 100644 Assets/Materials/Hero Cutout Occluder.mat create mode 100644 Assets/Materials/Hero Cutout Occluder.mat.meta create mode 100644 Assets/Scripts/HeroCutout.cs create mode 100644 Assets/Scripts/HeroCutout.cs.meta create mode 100644 Assets/Shaders/HeroCutout.hlsl create mode 100644 Assets/Shaders/HeroCutout.hlsl.meta create mode 100644 Assets/Shaders/HeroCutoutLit.shader create mode 100644 Assets/Shaders/HeroCutoutLit.shader.meta diff --git a/Assets/Materials/Hero Cutout Occluder.mat b/Assets/Materials/Hero Cutout Occluder.mat new file mode 100644 index 0000000..ae6d770 --- /dev/null +++ b/Assets/Materials/Hero Cutout Occluder.mat @@ -0,0 +1,123 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Hero Cutout Occluder + m_Shader: {fileID: 4800000, guid: 023c98a32f6cc00478e50479839530c5, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: [] + m_InvalidKeywords: [] + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: + RenderType: Opaque + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _DstBlendAlpha: 0 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 0 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 + - _ZWrite: 1 + m_Colors: + - _BaseColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + - _Color: {r: 0.5, g: 0.5, b: 0.5, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 diff --git a/Assets/Materials/Hero Cutout Occluder.mat.meta b/Assets/Materials/Hero Cutout Occluder.mat.meta new file mode 100644 index 0000000..7569908 --- /dev/null +++ b/Assets/Materials/Hero Cutout Occluder.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 284ac320f0449154dae9b92d90f5550b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Lobby.unity b/Assets/Scenes/Lobby.unity index d72cce8..a5d4aca 100644 --- a/Assets/Scenes/Lobby.unity +++ b/Assets/Scenes/Lobby.unity @@ -184,7 +184,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -296,7 +296,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -408,7 +408,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -520,7 +520,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -632,7 +632,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -856,7 +856,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 @@ -968,7 +968,7 @@ MeshRenderer: m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: - - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + - {fileID: 2100000, guid: 284ac320f0449154dae9b92d90f5550b, type: 2} m_StaticBatchInfo: firstSubMesh: 0 subMeshCount: 0 diff --git a/Assets/Scenes/Main.unity b/Assets/Scenes/Main.unity index 4ad0749..7f970b6 100644 --- a/Assets/Scenes/Main.unity +++ b/Assets/Scenes/Main.unity @@ -1823,6 +1823,7 @@ GameObject: m_Component: - component: {fileID: 1516578028} - component: {fileID: 1516578027} + - component: {fileID: 1516578029} m_Layer: 0 m_Name: GameManager m_TagString: Untagged @@ -1864,6 +1865,24 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1516578029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1516578026} + m_Enabled: 0 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7d67030b8dcdec489471b88c35dd78b, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::HeroCutout + orbitInput: {fileID: 0} + modes: {fileID: 0} + radius: 0.3 + feather: 0.1 + depthBias: 0.5 + heightOffset: 0 --- !u!21 &1752619484 Material: serializedVersion: 8 diff --git a/Assets/Scripts/HeroCutout.cs b/Assets/Scripts/HeroCutout.cs new file mode 100644 index 0000000..057c044 --- /dev/null +++ b/Assets/Scripts/HeroCutout.cs @@ -0,0 +1,94 @@ +using UnityEngine; +using Unity.Cinemachine; + +/// +/// Drives the screen-space radial "hero cutout". Every late frame it projects the local player to +/// screen space and feeds that position + a circle radius/feather + the player's eye-space depth into +/// two global shader properties (_HeroCutoutPosRadius, _HeroCutoutDepthOn) that the +/// Custom/HeroCutoutLit shader reads to clip occluder geometry between the camera and the +/// player - punching a soft see-through hole toward the character. +/// +/// The effect is only armed while the third-person orbit is the live +/// Cinemachine camera (i.e. Player Control / Paint mode). In first-person, free-cam, or while a menu +/// is open a different vcam is live, so the cutout disarms and occluders render solid. Disarming sets +/// the global "enabled" flag to 0, which also matches the zero-initialised default - so any scene +/// without this driver leaves cutout materials looking exactly like URP/Lit. +/// +/// Attach to a persistent scene object (e.g. the GameModeManager host). +/// +[DisallowMultipleComponent] +public class HeroCutout : MonoBehaviour +{ + [Tooltip("Orbit camera input whose CinemachineCamera must be live for the cutout to arm. Empty = found automatically.")] + public ThirdPersonOrbitInput orbitInput; + + [Tooltip("Game mode manager, used as a fallback source for the live player. Empty = found automatically.")] + public GameModeManager modes; + + [Header("Circle")] + [Tooltip("Radius of the see-through circle, as a fraction of screen height (0.13 = 13% of height).")] + [Range(0.02f, 0.6f)] public float radius = 0.13f; + + [Tooltip("Soft-edge width of the circle, as a fraction of screen height.")] + [Range(0f, 0.3f)] public float feather = 0.05f; + + [Tooltip("Metres added to the player's depth so geometry right at the player isn't clipped away.")] + public float depthBias = 0.5f; + + [Tooltip("Vertical offset (m) from the follow target where the circle centres (chest/head height).")] + public float heightOffset = 0f; + + static readonly int PosRadiusId = Shader.PropertyToID("_HeroCutoutPosRadius"); + static readonly int DepthOnId = Shader.PropertyToID("_HeroCutoutDepthOn"); + + private CinemachineCamera _orbitCam; + private CinemachineBrain _brain; + + private void Awake() + { + if (!orbitInput) orbitInput = FindFirstObjectByType(FindObjectsInactive.Include); + if (!modes) modes = FindFirstObjectByType(); + if (orbitInput) _orbitCam = orbitInput.GetComponent(); + } + + private void OnDisable() => Disarm(); + + private void LateUpdate() + { + Camera cam = Camera.main; + if (!cam) { Disarm(); return; } + + if (!_brain || _brain.gameObject != cam.gameObject) + _brain = cam.GetComponent(); + + if (!IsThirdPersonLive()) { Disarm(); return; } + + Transform target = ResolveHeroTarget(); + if (!target) { Disarm(); return; } + + Vector3 heroPos = target.position + Vector3.up * heightOffset; + Vector3 vp = cam.WorldToViewportPoint(heroPos); + if (vp.z <= 0f) { Disarm(); return; } // hero is behind the camera + + Shader.SetGlobalVector(PosRadiusId, new Vector4(vp.x, vp.y, radius, Mathf.Max(feather, 1e-4f))); + Shader.SetGlobalVector(DepthOnId, new Vector4(vp.z + depthBias, 1f, 0f, 0f)); + } + + /// True only when the orbit vcam is the live Cinemachine camera (third-person modes). + private bool IsThirdPersonLive() + { + if (!_orbitCam || !_brain) return false; + var live = _brain.ActiveVirtualCamera as CinemachineCamera; + return live && live == _orbitCam; + } + + private Transform ResolveHeroTarget() + { + if (_orbitCam && _orbitCam.Follow) return _orbitCam.Follow; + if (modes && modes.Player) return modes.Player.transform; + return null; + } + + /// Clears the "enabled" flag so cutout materials render as plain URP/Lit. + private void Disarm() => Shader.SetGlobalVector(DepthOnId, Vector4.zero); +} diff --git a/Assets/Scripts/HeroCutout.cs.meta b/Assets/Scripts/HeroCutout.cs.meta new file mode 100644 index 0000000..b3f46ea --- /dev/null +++ b/Assets/Scripts/HeroCutout.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c7d67030b8dcdec489471b88c35dd78b \ No newline at end of file diff --git a/Assets/Shaders/HeroCutout.hlsl b/Assets/Shaders/HeroCutout.hlsl new file mode 100644 index 0000000..584bc7d --- /dev/null +++ b/Assets/Shaders/HeroCutout.hlsl @@ -0,0 +1,46 @@ +#ifndef HERO_CUTOUT_INCLUDED +#define HERO_CUTOUT_INCLUDED + +// Screen-space radial "hero cutout": clips occluder fragments that sit inside a circle around the +// on-screen player AND in front of it, punching a clean see-through hole toward the character. +// +// These two globals are driven every frame by HeroCutout.cs (Shader.SetGlobalVector). They live +// OUTSIDE UnityPerMaterial, so the SRP Batcher is unaffected. When the effect is disabled +// (_HeroCutoutDepthOn.y < 0.5, also the zero-initialised default) ApplyHeroCutout early-outs and the +// shader renders exactly like URP/Lit. +// _HeroCutoutPosRadius : xy = hero viewport pos (0..1, bottom-left), z = radius, w = feather +// radius/feather are in normalized viewport-HEIGHT units +// _HeroCutoutDepthOn : x = hero eye-space depth (incl. bias), y = enabled (0/1) +float4 _HeroCutoutPosRadius; +float4 _HeroCutoutDepthOn; + +// Interleaved-gradient noise -> screen-door dither, gives the circle a soft edge with no extra +// textures or includes. +float HeroCutoutDither(float2 positionSS) +{ + return frac(52.9829189 * frac(dot(positionSS, float2(0.06711056, 0.00583715)))); +} + +void ApplyHeroCutout(float4 positionCS) +{ + if (_HeroCutoutDepthOn.y < 0.5) + return; + + // Flip-correct screen UV (matches Camera.WorldToViewportPoint's bottom-left convention). + float2 uv = GetNormalizedScreenSpaceUV(positionCS); + float2 delta = uv - _HeroCutoutPosRadius.xy; + delta.x *= _ScreenParams.x / max(_ScreenParams.y, 1.0); // aspect-correct -> a round circle + float dist = length(delta); + + float radius = _HeroCutoutPosRadius.z; + float feather = max(_HeroCutoutPosRadius.w, 1e-4); + float inside = 1.0 - smoothstep(radius - feather, radius, dist); // 1 inside, 0 outside + + // Only hole geometry between the camera and the hero; anything at/behind the player stays solid. + float eyeDepth = LinearEyeDepth(positionCS.z, _ZBufferParams); + float inFront = step(eyeDepth, _HeroCutoutDepthOn.x); + + float cut = inside * inFront; + clip(HeroCutoutDither(positionCS.xy) - cut); +} +#endif diff --git a/Assets/Shaders/HeroCutout.hlsl.meta b/Assets/Shaders/HeroCutout.hlsl.meta new file mode 100644 index 0000000..5d677b3 --- /dev/null +++ b/Assets/Shaders/HeroCutout.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8fbf575abd6dde145ac13a28b92a87a0 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Shaders/HeroCutoutLit.shader b/Assets/Shaders/HeroCutoutLit.shader new file mode 100644 index 0000000..94b65b3 --- /dev/null +++ b/Assets/Shaders/HeroCutoutLit.shader @@ -0,0 +1,581 @@ +// Drop-in clone of "Universal Render Pipeline/Lit" (URP 17) that adds a screen-space radial +// "hero cutout": occluder geometry between the third-person camera and the player is clipped away +// in a soft circle (see HeroCutout.hlsl + HeroCutout.cs). +// +// It is a faithful copy of URP's Lit.shader - same properties, keywords and includes, so material +// values transfer 1:1 and the inspector GUI keeps working. The ONLY change is in four passes +// (ForwardLit, ShadowCaster, DepthOnly, DepthNormals): the stock fragment entry point is replaced by +// a thin wrapper that runs ApplyHeroCutout() and then delegates to URP's original fragment. All +// shading is therefore URP's own - zero reimplementation, so it stays correct across URP updates. +Shader "Custom/HeroCutoutLit" +{ + Properties + { + // Specular vs Metallic workflow + _WorkflowMode("WorkflowMode", Float) = 1.0 + + [MainTexture] _BaseMap("Albedo", 2D) = "white" {} + [MainColor] _BaseColor("Color", Color) = (1,1,1,1) + + _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 + + _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 + _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 + + _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 + _MetallicGlossMap("Metallic", 2D) = "white" {} + + _SpecColor("Specular", Color) = (0.2, 0.2, 0.2) + _SpecGlossMap("Specular", 2D) = "white" {} + + [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 + [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 + + _BumpScale("Scale", Float) = 1.0 + _BumpMap("Normal Map", 2D) = "bump" {} + + _Parallax("Scale", Range(0.005, 0.08)) = 0.005 + _ParallaxMap("Height Map", 2D) = "black" {} + + _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 + _OcclusionMap("Occlusion", 2D) = "white" {} + + [HDR] _EmissionColor("Color", Color) = (0,0,0) + _EmissionMap("Emission", 2D) = "white" {} + + _DetailMask("Detail Mask", 2D) = "white" {} + _DetailAlbedoMapScale("Scale", Range(0.0, 2.0)) = 1.0 + _DetailAlbedoMap("Detail Albedo x2", 2D) = "linearGrey" {} + _DetailNormalMapScale("Scale", Range(0.0, 2.0)) = 1.0 + [Normal] _DetailNormalMap("Normal Map", 2D) = "bump" {} + + // SRP batching compatibility for Clear Coat (Not used in Lit) + [HideInInspector] _ClearCoatMask("_ClearCoatMask", Float) = 0.0 + [HideInInspector] _ClearCoatSmoothness("_ClearCoatSmoothness", Float) = 0.0 + + // Blending state + _Surface("__surface", Float) = 0.0 + _Blend("__blend", Float) = 0.0 + _Cull("__cull", Float) = 2.0 + [ToggleUI] _AlphaClip("__clip", Float) = 0.0 + [HideInInspector] _SrcBlend("__src", Float) = 1.0 + [HideInInspector] _DstBlend("__dst", Float) = 0.0 + [HideInInspector] _SrcBlendAlpha("__srcA", Float) = 1.0 + [HideInInspector] _DstBlendAlpha("__dstA", Float) = 0.0 + [HideInInspector] _ZWrite("__zw", Float) = 1.0 + [HideInInspector] _BlendModePreserveSpecular("_BlendModePreserveSpecular", Float) = 1.0 + [HideInInspector] _AlphaToMask("__alphaToMask", Float) = 0.0 + [HideInInspector] _AddPrecomputedVelocity("_AddPrecomputedVelocity", Float) = 0.0 + [HideInInspector] _XRMotionVectorsPass("_XRMotionVectorsPass", Float) = 1.0 + + [ToggleUI] _ReceiveShadows("Receive Shadows", Float) = 1.0 + // Editmode props + _QueueOffset("Queue offset", Float) = 0.0 + + // ObsoleteProperties + [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} + [HideInInspector] _Color("Base Color", Color) = (1, 1, 1, 1) + [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0 + [HideInInspector] _Glossiness("Smoothness", Float) = 0.0 + [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0 + + [HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {} + [HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {} + [HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {} + } + + SubShader + { + Tags + { + "RenderType" = "Opaque" + "RenderPipeline" = "UniversalPipeline" + "UniversalMaterialType" = "Lit" + "IgnoreProjector" = "True" + } + LOD 300 + + // ------------------------------------------------------------------ + // Forward pass. Shades all light in a single pass. GI + emission + Fog + Pass + { + Name "ForwardLit" + Tags + { + "LightMode" = "UniversalForward" + } + + // ------------------------------------- + // Render State Commands + Blend[_SrcBlend][_DstBlend], [_SrcBlendAlpha][_DstBlendAlpha] + ZWrite[_ZWrite] + Cull[_Cull] + AlphaToMask[_AlphaToMask] + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + #pragma vertex LitPassVertex + #pragma fragment HeroForwardFragment + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local _NORMALMAP + #pragma shader_feature_local _PARALLAXMAP + #pragma shader_feature_local _RECEIVE_SHADOWS_OFF + #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED + #pragma shader_feature_local_fragment _SURFACE_TYPE_TRANSPARENT + #pragma shader_feature_local_fragment _ALPHATEST_ON + #pragma shader_feature_local_fragment _ _ALPHAPREMULTIPLY_ON _ALPHAMODULATE_ON + #pragma shader_feature_local_fragment _EMISSION + #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP + #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + #pragma shader_feature_local_fragment _OCCLUSIONMAP + #pragma shader_feature_local_fragment _SPECULARHIGHLIGHTS_OFF + #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF + #pragma shader_feature_local_fragment _SPECULAR_SETUP + + // ------------------------------------- + // Universal Pipeline keywords + #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 _ _REFLECTION_PROBE_BLENDING + #pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION + #pragma multi_compile_fragment _ _REFLECTION_PROBE_ATLAS + #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 _ _SCREEN_SPACE_IRRADIANCE + #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3 + #pragma multi_compile_fragment _ _LIGHT_COOKIES + #pragma multi_compile _ _LIGHT_LAYERS + #pragma multi_compile _ _CLUSTER_LIGHT_LOOP + #include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl" + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" + + + // ------------------------------------- + // Unity defined keywords + #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING + #pragma multi_compile _ SHADOWS_SHADOWMASK + #pragma multi_compile _ DIRLIGHTMAP_COMBINED + #pragma multi_compile _ LIGHTMAP_ON + #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile_fragment _ REFLECTION_PROBE_ROTATION + #pragma multi_compile _ DYNAMICLIGHTMAP_ON + #pragma multi_compile _ USE_LEGACY_LIGHTMAPS + #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma multi_compile_fragment _ DEBUG_DISPLAY + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Fog.hlsl" + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl" + + //-------------------------------------- + // GPU Instancing + #pragma multi_compile_instancing + #pragma instancing_options renderinglayer + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitForwardPass.hlsl" + #include "HeroCutout.hlsl" + + // Radial cutout, then delegate to URP's stock LitPassFragment for all shading. + void HeroForwardFragment( + Varyings input + , out half4 outColor : SV_Target0 + #ifdef _WRITE_RENDERING_LAYERS + , out uint outRenderingLayers : SV_Target1 + #endif + ) + { + ApplyHeroCutout(input.positionCS); + LitPassFragment(input, outColor + #ifdef _WRITE_RENDERING_LAYERS + , outRenderingLayers + #endif + ); + } + ENDHLSL + } + + Pass + { + Name "ShadowCaster" + Tags + { + "LightMode" = "ShadowCaster" + } + + // ------------------------------------- + // Render State Commands + ZWrite On + ZTest LEqual + ColorMask 0 + Cull[_Cull] + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + // NOTE: shadows are intentionally NOT cut out. ShadowCaster runs in light clip space, + // so the camera-space radial mask in ApplyHeroCutout would be meaningless there (and the + // occluder is conceptually "still there", just visually see-through). Stock fragment. + #pragma vertex ShadowPassVertex + #pragma fragment ShadowPassFragment + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local _ALPHATEST_ON + #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + + //-------------------------------------- + // GPU Instancing + #pragma multi_compile_instancing + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + // ------------------------------------- + // Universal Pipeline keywords + + // ------------------------------------- + // Unity defined keywords + #pragma multi_compile _ LOD_FADE_CROSSFADE + + // This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias + #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl" + ENDHLSL + } + + Pass + { + Name "GBuffer" + Tags + { + "LightMode" = "UniversalGBuffer" + } + + // ------------------------------------- + // Render State Commands + ZWrite[_ZWrite] + ZTest LEqual + Cull[_Cull] + + HLSLPROGRAM + #pragma target 4.5 + + // Deferred Rendering Path does not support the OpenGL-based graphics API: + // Desktop OpenGL, OpenGL ES 3.0, WebGL 2.0. + #pragma exclude_renderers gles3 glcore + + // ------------------------------------- + // Shader Stages + #pragma vertex LitGBufferPassVertex + #pragma fragment LitGBufferPassFragment + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local _NORMALMAP + #pragma shader_feature_local_fragment _ALPHATEST_ON + //#pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON + #pragma shader_feature_local_fragment _EMISSION + #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP + #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + #pragma shader_feature_local_fragment _OCCLUSIONMAP + #pragma shader_feature_local _PARALLAXMAP + #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED + + #pragma shader_feature_local_fragment _SPECULARHIGHLIGHTS_OFF + #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF + #pragma shader_feature_local_fragment _SPECULAR_SETUP + #pragma shader_feature_local _RECEIVE_SHADOWS_OFF + + // ------------------------------------- + // Universal Pipeline keywords + #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 _ _ADDITIONAL_LIGHT_SHADOWS + #pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING + #pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION + #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH + #pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3 + #pragma multi_compile_fragment _ _RENDER_PASS_ENABLED + #pragma multi_compile _ _CLUSTER_LIGHT_LOOP + #pragma multi_compile _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX + #include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl" + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" + + // ------------------------------------- + // Unity defined keywords + #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING + #pragma multi_compile _ SHADOWS_SHADOWMASK + #pragma multi_compile _ DIRLIGHTMAP_COMBINED + #pragma multi_compile _ LIGHTMAP_ON + #pragma multi_compile_fragment _ LIGHTMAP_BICUBIC_SAMPLING + #pragma multi_compile_fragment _ REFLECTION_PROBE_ROTATION + #pragma multi_compile _ DYNAMICLIGHTMAP_ON + #pragma multi_compile _ USE_LEGACY_LIGHTMAPS + #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT + #pragma multi_compile_fragment _ _SCREEN_SPACE_IRRADIANCE + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl" + + //-------------------------------------- + // GPU Instancing + #pragma multi_compile_instancing + #pragma instancing_options renderinglayer + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitGBufferPass.hlsl" + ENDHLSL + } + + Pass + { + Name "DepthOnly" + Tags + { + "LightMode" = "DepthOnly" + } + + // ------------------------------------- + // Render State Commands + ZWrite On + ColorMask R + Cull[_Cull] + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + #pragma vertex DepthOnlyVertex + #pragma fragment HeroDepthOnlyFragment + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local _ALPHATEST_ON + #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + + // ------------------------------------- + // Unity defined keywords + #pragma multi_compile _ LOD_FADE_CROSSFADE + + //-------------------------------------- + // GPU Instancing + #pragma multi_compile_instancing + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl" + #include "HeroCutout.hlsl" + + half HeroDepthOnlyFragment(Varyings input) : SV_TARGET + { + ApplyHeroCutout(input.positionCS); + return DepthOnlyFragment(input); + } + ENDHLSL + } + + // This pass is used when drawing to a _CameraNormalsTexture texture + Pass + { + Name "DepthNormals" + Tags + { + "LightMode" = "DepthNormals" + } + + // ------------------------------------- + // Render State Commands + ZWrite On + Cull[_Cull] + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + #pragma vertex DepthNormalsVertex + #pragma fragment HeroDepthNormalsFragment + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local _NORMALMAP + #pragma shader_feature_local _PARALLAXMAP + #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED + #pragma shader_feature_local _ALPHATEST_ON + #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + + // ------------------------------------- + // Unity defined keywords + #pragma multi_compile _ LOD_FADE_CROSSFADE + + // ------------------------------------- + // Universal Pipeline keywords + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl" + + //-------------------------------------- + // GPU Instancing + #pragma multi_compile_instancing + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitDepthNormalsPass.hlsl" + #include "HeroCutout.hlsl" + + void HeroDepthNormalsFragment( + Varyings input + , out half4 outNormalWS : SV_Target0 + #ifdef _WRITE_RENDERING_LAYERS + , out uint outRenderingLayers : SV_Target1 + #endif + ) + { + ApplyHeroCutout(input.positionCS); + DepthNormalsFragment(input, outNormalWS + #ifdef _WRITE_RENDERING_LAYERS + , outRenderingLayers + #endif + ); + } + ENDHLSL + } + + // This pass it not used during regular rendering, only for lightmap baking. + Pass + { + Name "Meta" + Tags + { + "LightMode" = "Meta" + } + + // ------------------------------------- + // Render State Commands + Cull Off + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + #pragma vertex UniversalVertexMeta + #pragma fragment UniversalFragmentMetaLit + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local_fragment _SPECULAR_SETUP + #pragma shader_feature_local_fragment _EMISSION + #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP + #pragma shader_feature_local_fragment _ALPHATEST_ON + #pragma shader_feature_local_fragment _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A + #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED + #pragma shader_feature_local_fragment _SPECGLOSSMAP + #pragma shader_feature EDITOR_VISUALIZATION + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitMetaPass.hlsl" + + ENDHLSL + } + + Pass + { + Name "Universal2D" + Tags + { + "LightMode" = "Universal2D" + } + + // ------------------------------------- + // Render State Commands + Blend[_SrcBlend][_DstBlend] + ZWrite[_ZWrite] + Cull[_Cull] + + HLSLPROGRAM + #pragma target 2.0 + + // ------------------------------------- + // Shader Stages + #pragma vertex vert + #pragma fragment frag + + // ------------------------------------- + // Material Keywords + #pragma shader_feature_local_fragment _ALPHATEST_ON + #pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON + + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl" + + // ------------------------------------- + // Includes + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include "Packages/com.unity.render-pipelines.universal/Shaders/Utils/Universal2D.hlsl" + ENDHLSL + } + + Pass + { + Name "MotionVectors" + Tags { "LightMode" = "MotionVectors" } + ColorMask RG + + HLSLPROGRAM + #pragma shader_feature_local _ALPHATEST_ON + #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma shader_feature_local_vertex _ADD_PRECOMPUTED_VELOCITY + + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl" + ENDHLSL + } + + Pass + { + Name "XRMotionVectors" + Tags { "LightMode" = "XRMotionVectors" } + ColorMask RGBA + + // Stencil write for obj motion pixels + Stencil + { + WriteMask 1 + Ref 1 + Comp Always + Pass Replace + } + + HLSLPROGRAM + #pragma shader_feature_local _ALPHATEST_ON + #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma shader_feature_local_vertex _ADD_PRECOMPUTED_VELOCITY + #define APPLICATION_SPACE_WARP_MOTION 1 + + #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" + #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl" + ENDHLSL + } + } + + FallBack "Hidden/Universal Render Pipeline/FallbackError" + CustomEditor "UnityEditor.Rendering.Universal.ShaderGUI.LitShader" +} diff --git a/Assets/Shaders/HeroCutoutLit.shader.meta b/Assets/Shaders/HeroCutoutLit.shader.meta new file mode 100644 index 0000000..f9081c8 --- /dev/null +++ b/Assets/Shaders/HeroCutoutLit.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 023c98a32f6cc00478e50479839530c5 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: