Unity URP之通过Feature实现毛皮效果

以下代码来源于第三方插件。

Feature代码:

  1 using System.Collections.Generic;
  2 using UnityEngine;
  3 using UnityEngine.Experimental.Rendering.Universal;
  4 using UnityEngine.Rendering;
  5 using UnityEngine.Rendering.Universal;
  6 
  7 //[ExecuteInEditMode]
  8 public class FurRenderFeature : ScriptableRendererFeature
  9 {
 10     [System.Serializable]
 11     public class FilterSettings
 12     {
 13         // TODO: expose opaque, transparent, all ranges as drop down
 14         public RenderQueueType RenderQueueType;
 15         public LayerMask LayerMask = 1;
 16         public string[] PassNames;
 17 
 18         public FilterSettings()
 19         {
 20             RenderQueueType = RenderQueueType.Opaque;
 21             LayerMask =  ~0;
 22             PassNames = new string[] {"FurRendererBase", "FurRendererLayer"};
 23         }
 24     }
 25 
 26     public static FurRenderFeature instance;
 27     
 28     /// <summary>
 29     /// This function is called when the object becomes enable and active.
 30     /// </summary>
 31     ///
 32     [System.Serializable]
 33     public class PassSettings
 34     {
 35         public string passTag = "FurRenderer";
 36         [Header("Settings")]
 37         public bool ShouldRender = true;
 38         [Tooltip("Set Layer Num")]
 39         [Range(1, 200)]public int PassLayerNum = 20;
 40         [Range(1000, 5000)] public int QueueMin = 2000;
 41         [Range(1000, 5000)] public int QueueMax = 5000;
 42         public RenderPassEvent PassEvent = RenderPassEvent.AfterRenderingSkybox;
 43 
 44         public FilterSettings filterSettings = new FilterSettings();
 45     }
 46 
 47     public class FurRenderPass : ScriptableRenderPass
 48     {
 49         string m_ProfilerTag;
 50         RenderQueueType renderQueueType;
 51         private PassSettings settings;
 52         private FurRenderFeature furRenderFeature = null;
 53         public List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>();
 54         private ShaderTagId shadowCasterSTI = new ShaderTagId("ShadowCaster");
 55         private FilteringSettings filter;
 56         public Material overrideMaterial { get; set; }
 57         public int overrideMaterialPassIndex { get; set; }
 58 
 59         public FurRenderPass(PassSettings setting, FurRenderFeature render,FilterSettings filterSettings)
 60         {
 61             m_ProfilerTag = setting.passTag;
 62             string[] shaderTags = filterSettings.PassNames;
 63             this.settings = setting;
 64             this.renderQueueType = filterSettings.RenderQueueType;
 65             furRenderFeature = render;
 66             //过滤设定
 67             RenderQueueRange queue = new RenderQueueRange();
 68             queue.lowerBound = setting.QueueMin;
 69             queue.upperBound = setting.QueueMax;
 70             filter = new FilteringSettings(queue,filterSettings.LayerMask);
 71             if (shaderTags != null && shaderTags.Length > 0)
 72             {
 73                 foreach (var passName in shaderTags)
 74                     m_ShaderTagIdList.Add(new ShaderTagId(passName));
 75             }
 76         }
 77 
 78         // This method is called before executing the render pass.
 79         // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
 80         // When empty this render pass will render to the active camera render target.
 81         // You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
 82         // The render pipeline will ensure target setup and clearing happens in an performance manner.
 83         public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
 84         {
 85         }
 86 
 87         // Here you can implement the rendering logic.
 88         // Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
 89         // https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
 90         // You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
 91         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
 92         {
 93             SortingCriteria sortingCriteria = (renderQueueType == RenderQueueType.Transparent)
 94                 ? SortingCriteria.CommonTransparent
 95                 : renderingData.cameraData.defaultOpaqueSortFlags;
 96             CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
 97             //=============================================================
 98             //draw objects(e.g. reflective wet ground plane) with lightmode "MobileSSPRWater", which will sample _MobileSSPR_ColorRT
 99             DrawingSettings baseDrawingSetting, layerDrawingSetting;
100             //BaseLayer DrawingSetting
101             if (m_ShaderTagIdList.Count > 0)
102                 baseDrawingSetting = CreateDrawingSettings(m_ShaderTagIdList[0], ref renderingData,
103                     renderingData.cameraData.defaultOpaqueSortFlags);
104             else return;
105             if(m_ShaderTagIdList.Count > 1)
106             layerDrawingSetting = CreateDrawingSettings(m_ShaderTagIdList[1], ref renderingData,
107                 renderingData.cameraData.defaultOpaqueSortFlags);
108             else return;
109             float inter = 1.0f / settings.PassLayerNum;
110             //BaseLayer
111             cmd.Clear();
112             cmd.SetGlobalFloat("_FUR_OFFSET", 0);
113             context.ExecuteCommandBuffer(cmd);
114             context.DrawRenderers(renderingData.cullResults,ref baseDrawingSetting,ref filter);
115             //TransparentLayer
116             for(int i = 1; i < settings.PassLayerNum; i++)
117             {
118                 cmd.Clear();
119                 cmd.SetGlobalFloat("_FUR_OFFSET", i * inter);
120                 context.ExecuteCommandBuffer(cmd);
121                 context.DrawRenderers(renderingData.cullResults,ref layerDrawingSetting,ref filter);
122             }
123             CommandBufferPool.Release(cmd);
124         }
125 
126         /// Cleanup any allocated resources that were created during the execution of this render pass.
127         public override void FrameCleanup(CommandBuffer cmd)
128         {
129         }
130     }
131     public PassSettings settings = new PassSettings();
132     FurRenderPass m_ScriptablePass;
133 
134     public override void Create()
135     {
136         instance = this;
137         FilterSettings filter = settings.filterSettings;
138         m_ScriptablePass = new FurRenderPass(settings, this, filter);
139         // Configures where the render pass should be injected.
140         m_ScriptablePass.renderPassEvent = settings.PassEvent;
141     }
142 
143     // Here you can inject one or multiple render passes in the renderer.
144     // This method is called when setting up the renderer once per-camera.
145     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
146     {
147         renderer.EnqueuePass(m_ScriptablePass);
148     }
149 }
View Code

毛皮shader:

  1 Shader "LXShader/Other/MultiPassFurModified"
  2 {
  3     Properties
  4     {
  5        [Header(Macro)]
  6         [Toggle(_TANGENT_TO_WORLD)] _TangentToWorld("Tangent To World", Float) = 0
  7         [Toggle(_GI_ON)] _GI_ON("GIOn", Float) = 0
  8         [Toggle(_RECEIVE_SHADOWS)] _RECEIVE_SHADOWS("Receive Shadow", Float) = 0
  9         [KeywordEnum(On,Off)] _NORMALMAP_URP("Mormal Map", Float) = 0
 10         [Header(Main)]
 11         [MainColor]_Color("Color", Color) = (1,1,1,1)
 12         _MainTex("Albedo", 2D) = "white" {}
 13 
 14         _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5
 15 
 16         _BumpScale("Noramal Scale", Range(0,1)) = 1.0
 17         _BumpMap("Normal Map", 2D) = "bump" {}
 18 
 19         [Enum(UV0,0,UV1,1)] _UVSec("UV Set for secondary textures", Float) = 0
 20 
 21         [Space(20)]
 22         _FabricScatterColor("Fabric Scatter Color", Color) = (1,1,1,1)
 23         _FabricScatterScale("Fabric Scatter Scale", Range(0, 1)) = 0
 24         
 25         [Space(20)]
 26         _LayerTex("Layer", 2D) = "white" {}
 27         _FurLength("Fur Length", Range(.0002, 10)) = .25
 28         _Cutoff("Alpha Cutoff", Range(0,1)) = 0.5 // how "thick"
 29         _CutoffEnd("Alpha Cutoff end", Range(0,1)) = 0.5 // how thick they are at the end
 30         _EdgeFade("Edge Fade", Range(0,1)) = 0.4
 31         _Gravity("Gravity Direction", Vector) = (0,-1,0,0)
 32         _GravityStrength("Gravity Strength", Range(0,1)) = 0.25
 33         _FlowMap("Flow Map", 2D) = "gray"{}
 34         _UVOffset("UVOffset",Range(0,1))=0
 35         [Header(Shadow)]
 36         _ShadowColor("Shadow Color", Color) = (0,0,0,0)
 37         _ShadowLerp("Shadow AO",Range(0,1)) = 1
 38         // Blending state
 39         [Header(Settings)]
 40         _Mode("__mode", Float) = 0.0
 41         [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend Mode", Float) = 5
 42         [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend Mode", Float) = 10
 43         [Toggle]_ZWrite("__zw", Float) = 1.0
 44         [Toggle(_ALPHATEST_ON)]_ALPHATEST_ON("_ALPHATEST_ON",Float) =1
 45     }
 46     SubShader
 47     {
 48         Tags { "RenderType"="Opaque"  "PerformanceChecks" = "False"}
 49 
 50         LOD 100
 51         HLSLINCLUDE
 52         #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
 53         #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
 54         #define UNITY_SETUP_BRDF_INPUT MetallicSetup
 55         #define _NORMALMAP_URP 1
 56         #define _FABRIC_URP 1
 57         #define _FUR_URP 1
 58 
 59         sampler2D _LayerTex;
 60         sampler2D   _BumpMap;
 61         sampler2D _FlowMap;
 62         sampler2D _MainTex;
 63         sampler2D   _OcclusionMap;
 64 
 65         CBUFFER_START(UnityPerMaterial)
 66         half _UVOffset;
 67         half3 _FabricScatterColor;
 68         half  _FabricScatterScale;
 69         float4 _MainTex_ST;
 70         float4 _LayerTex_ST;
 71         half _Glossiness;
 72         half _FurLength;
 73         half _GravityStrength;
 74         half4 _Color;
 75         half3 _Gravity;
 76         half _CutoffEnd;
 77         half _EdgeFade;
 78         half        _OcclusionStrength;
 79         half        _Cutoff;
 80         half        _BumpScale;
 81         float _Metallic;
 82 
 83         // //PBR
 84         float3 _Albedo;
 85         
 86         float3 _Specular;
 87         float _Smoothness;
 88         float _Occlusion;
 89         float3 _Emission;
 90         float _Alpha;
 91         float4 _ShadowColor;
 92         half _ShadowLerp;
 93         CBUFFER_END
 94         half _FUR_OFFSET;
 95 
 96         //
 97         ENDHLSL
 98         
 99         Pass
100         {
101            Name "FurRender"
102             Tags{ "LightMode" = "FurRendererBase"}
103             //Blend[_SrcBlend][_DstBlend]
104             ZWrite[_ZWrite]
105             HLSLPROGRAM
106             // make fog work
107             #pragma multi_compile_fog
108             #pragma shader_feature _ _TANGENT_TO_WORLD
109             //#pragma shader_feature _ _PARALLAXMAP
110             #pragma shader_feature _ _GI_ON
111             #pragma multi_compile _ LIGHTMAP_ON
112             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
113             #pragma shader_feature _NORMALMAP
114             #pragma shader_feature _ _RECEIVE_SHADOWS
115             //#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
116             #pragma shader_feature _EMISSION
117             #pragma shader_feature _METALLICGLOSSMAP
118             #pragma shader_feature ___ _DETAIL_MULX2
119             #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
120             #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
121             #pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
122             #pragma shader_feature _NORMALMAP_URP_ON _NORMALMAP_URP_OFF
123             // #define SHADER_TARGET 100
124             
125             #pragma vertex vert_LayerBase
126             #pragma fragment frag_LayerBase
127 
128             #include "FurCoreData.hlsl"
129 
130             ENDHLSL
131         }
132         Pass
133         {
134            Name "FurRender"
135             Tags{ "LightMode" = "FurRendererLayer"}
136             Blend[_SrcBlend][_DstBlend]
137             ZWrite[_ZWrite]
138             HLSLPROGRAM
139             // make fog work
140             #pragma multi_compile_fog
141             #pragma shader_feature _ _TANGENT_TO_WORLD
142             //#pragma shader_feature _ _PARALLAXMAP
143             #pragma shader_feature _ _GI_ON
144             #pragma multi_compile _ LIGHTMAP_ON
145             #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
146             #pragma shader_feature _NORMALMAP
147             #pragma shader_feature _ _RECEIVE_SHADOWS
148             //#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
149             #pragma shader_feature _EMISSION
150             #pragma shader_feature _METALLICGLOSSMAP
151             #pragma shader_feature ___ _DETAIL_MULX2
152             #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
153             #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF
154             #pragma shader_feature _ _GLOSSYREFLECTIONS_OFF
155             #pragma shader_feature _NORMALMAP_URP_ON _NORMALMAP_URP_OFF
156             
157             #pragma vertex vert_LayerBase
158             #pragma fragment frag_LayerBase
159 
160             #include "FurCoreData.hlsl"
161 
162             ENDHLSL
163         }
164         Pass
165         {
166             
167             Name "ShadowCaster"
168             Tags { "LightMode"="ShadowCaster" }
169 
170             ZWrite On
171             ZTest LEqual
172 
173             HLSLPROGRAM
174             #define ASE_SRP_VERSION 70301
175 
176             #pragma prefer_hlslcc gles
177             #pragma exclude_renderers d3d11_9x
178 
179             #pragma vertex vert
180             #pragma fragment frag
181 
182             #define SHADERPASS_SHADOWCASTER
183 
184             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
185             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
186             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
187             #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
188 
189             
190 
191             struct VertexInput
192             {
193                 float4 vertex : POSITION;
194                 float3 ase_normal : NORMAL;
195                 
196                 UNITY_VERTEX_INPUT_INSTANCE_ID
197             };
198 
199             struct VertexOutput
200             {
201                 float4 clipPos : SV_POSITION;
202                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
203                 float3 worldPos : TEXCOORD0;
204                 #endif
205                 #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) && defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
206                 float4 shadowCoord : TEXCOORD1;
207                 #endif
208                 
209                 UNITY_VERTEX_INPUT_INSTANCE_ID
210                 UNITY_VERTEX_OUTPUT_STEREO
211             };
212 
213             CBUFFER_START(UnityPerMaterial)
214                         #ifdef _TRANSMISSION_ASE
215                 float _TransmissionShadow;
216             #endif
217             #ifdef _TRANSLUCENCY_ASE
218                 float _TransStrength;
219                 float _TransNormal;
220                 float _TransScattering;
221                 float _TransDirect;
222                 float _TransAmbient;
223                 float _TransShadow;
224             #endif
225             #ifdef TESSELLATION_ON
226                 float _TessPhongStrength;
227                 float _TessValue;
228                 float _TessMin;
229                 float _TessMax;
230                 float _TessEdgeLength;
231                 float _TessMaxDisp;
232             #endif
233             CBUFFER_END
234             
235 
236             
237             float3 _LightDirection;
238 
239             VertexOutput VertexFunction( VertexInput v )
240             {
241                 VertexOutput o;
242                 UNITY_SETUP_INSTANCE_ID(v);
243                 UNITY_TRANSFER_INSTANCE_ID(v, o);
244                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );
245 
246                 
247                 #ifdef ASE_ABSOLUTE_VERTEX_POS
248                     float3 defaultVertexValue = v.vertex.xyz;
249                 #else
250                     float3 defaultVertexValue = float3(0, 0, 0);
251                 #endif
252                 float3 vertexValue = defaultVertexValue;
253                 #ifdef ASE_ABSOLUTE_VERTEX_POS
254                     v.vertex.xyz = vertexValue;
255                 #else
256                     v.vertex.xyz += vertexValue;
257                 #endif
258 
259                 v.ase_normal = v.ase_normal;
260 
261                 float3 positionWS = TransformObjectToWorld( v.vertex.xyz );
262                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
263                 o.worldPos = positionWS;
264                 #endif
265                 float3 normalWS = TransformObjectToWorldDir(v.ase_normal);
266 
267                 float4 clipPos = TransformWorldToHClip( ApplyShadowBias( positionWS, normalWS, _LightDirection ) );
268 
269                 #if UNITY_REVERSED_Z
270                     clipPos.z = min(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
271                 #else
272                     clipPos.z = max(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
273                 #endif
274                 #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) && defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
275                     VertexPositionInputs vertexInput = (VertexPositionInputs)0;
276                     vertexInput.positionWS = positionWS;
277                     vertexInput.positionCS = clipPos;
278                     o.shadowCoord = GetShadowCoord( vertexInput );
279                 #endif
280                 o.clipPos = clipPos;
281                 return o;
282             }
283 
284             #if defined(TESSELLATION_ON)
285             struct VertexControl
286             {
287                 float4 vertex : INTERNALTESSPOS;
288                 float3 ase_normal : NORMAL;
289                 
290                 UNITY_VERTEX_INPUT_INSTANCE_ID
291             };
292 
293             struct TessellationFactors
294             {
295                 float edge[3] : SV_TessFactor;
296                 float inside : SV_InsideTessFactor;
297             };
298 
299             VertexControl vert ( VertexInput v )
300             {
301                 VertexControl o;
302                 UNITY_SETUP_INSTANCE_ID(v);
303                 UNITY_TRANSFER_INSTANCE_ID(v, o);
304                 o.vertex = v.vertex;
305                 o.ase_normal = v.ase_normal;
306                 
307                 return o;
308             }
309 
310             TessellationFactors TessellationFunction (InputPatch<VertexControl,3> v)
311             {
312                 TessellationFactors o;
313                 float4 tf = 1;
314                 float tessValue = _TessValue; float tessMin = _TessMin; float tessMax = _TessMax;
315                 float edgeLength = _TessEdgeLength; float tessMaxDisp = _TessMaxDisp;
316                 #if defined(ASE_FIXED_TESSELLATION)
317                 tf = FixedTess( tessValue );
318                 #elif defined(ASE_DISTANCE_TESSELLATION)
319                 tf = DistanceBasedTess(v[0].vertex, v[1].vertex, v[2].vertex, tessValue, tessMin, tessMax, GetObjectToWorldMatrix(), _WorldSpaceCameraPos );
320                 #elif defined(ASE_LENGTH_TESSELLATION)
321                 tf = EdgeLengthBasedTess(v[0].vertex, v[1].vertex, v[2].vertex, edgeLength, GetObjectToWorldMatrix(), _WorldSpaceCameraPos, _ScreenParams );
322                 #elif defined(ASE_LENGTH_CULL_TESSELLATION)
323                 tf = EdgeLengthBasedTessCull(v[0].vertex, v[1].vertex, v[2].vertex, edgeLength, tessMaxDisp, GetObjectToWorldMatrix(), _WorldSpaceCameraPos, _ScreenParams, unity_CameraWorldClipPlanes );
324                 #endif
325                 o.edge[0] = tf.x; o.edge[1] = tf.y; o.edge[2] = tf.z; o.inside = tf.w;
326                 return o;
327             }
328 
329             [domain("tri")]
330             [partitioning("fractional_odd")]
331             [outputtopology("triangle_cw")]
332             [patchconstantfunc("TessellationFunction")]
333             [outputcontrolpoints(3)]
334             VertexControl HullFunction(InputPatch<VertexControl, 3> patch, uint id : SV_OutputControlPointID)
335             {
336                return patch[id];
337             }
338 
339             [domain("tri")]
340             VertexOutput DomainFunction(TessellationFactors factors, OutputPatch<VertexControl, 3> patch, float3 bary : SV_DomainLocation)
341             {
342                 VertexInput o = (VertexInput) 0;
343                 o.vertex = patch[0].vertex * bary.x + patch[1].vertex * bary.y + patch[2].vertex * bary.z;
344                 o.ase_normal = patch[0].ase_normal * bary.x + patch[1].ase_normal * bary.y + patch[2].ase_normal * bary.z;
345                 
346                 #if defined(ASE_PHONG_TESSELLATION)
347                 float3 pp[3];
348                 for (int i = 0; i < 3; ++i)
349                     pp[i] = o.vertex.xyz - patch[i].ase_normal * (dot(o.vertex.xyz, patch[i].ase_normal) - dot(patch[i].vertex.xyz, patch[i].ase_normal));
350                 float phongStrength = _TessPhongStrength;
351                 o.vertex.xyz = phongStrength * (pp[0]*bary.x + pp[1]*bary.y + pp[2]*bary.z) + (1.0f-phongStrength) * o.vertex.xyz;
352                 #endif
353                 UNITY_TRANSFER_INSTANCE_ID(patch[0], o);
354                 return VertexFunction(o);
355             }
356             #else
357             VertexOutput vert ( VertexInput v )
358             {
359                 return VertexFunction( v );
360             }
361             #endif
362 
363             half4 frag(VertexOutput IN  ) : SV_TARGET
364             {
365                 UNITY_SETUP_INSTANCE_ID( IN );
366                 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX( IN );
367                 
368                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
369                 float3 WorldPosition = IN.worldPos;
370                 #endif
371                 float4 ShadowCoords = float4( 0, 0, 0, 0 );
372 
373                 #if defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
374                     #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
375                         ShadowCoords = IN.shadowCoord;
376                     #elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
377                         ShadowCoords = TransformWorldToShadowCoord( WorldPosition );
378                     #endif
379                 #endif
380 
381                 
382                 float Alpha = 1;
383                 float AlphaClipThreshold = 0.5;
384 
385                 #ifdef _ALPHATEST_ON
386                     clip(Alpha - AlphaClipThreshold);
387                 #endif
388 
389                 #ifdef LOD_FADE_CROSSFADE
390                     LODDitheringTransition( IN.clipPos.xyz, unity_LODFade.x );
391                 #endif
392                 return 0;
393             }
394 
395             ENDHLSL
396         }    
397         Pass
398         {
399             
400             Name "DepthOnly"
401             Tags { "LightMode"="DepthOnly" }
402 
403             ZWrite On
404             ColorMask 0
405 
406             HLSLPROGRAM
407             #define ASE_SRP_VERSION 70301
408 
409             #pragma prefer_hlslcc gles
410             #pragma exclude_renderers d3d11_9x
411 
412             #pragma vertex vert
413             #pragma fragment frag
414 
415             #define SHADERPASS_DEPTHONLY
416 
417             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
418             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
419             #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
420             #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
421 
422             
423 
424             struct VertexInput
425             {
426                 float4 vertex : POSITION;
427                 float3 ase_normal : NORMAL;
428                 
429                 UNITY_VERTEX_INPUT_INSTANCE_ID
430             };
431 
432             struct VertexOutput
433             {
434                 float4 clipPos : SV_POSITION;
435                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
436                 float3 worldPos : TEXCOORD0;
437                 #endif
438                 #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) && defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
439                 float4 shadowCoord : TEXCOORD1;
440                 #endif
441                 
442                 UNITY_VERTEX_INPUT_INSTANCE_ID
443                 UNITY_VERTEX_OUTPUT_STEREO
444             };
445 
446             CBUFFER_START(UnityPerMaterial)
447                         #ifdef _TRANSMISSION_ASE
448                 float _TransmissionShadow;
449             #endif
450             #ifdef _TRANSLUCENCY_ASE
451                 float _TransStrength;
452                 float _TransNormal;
453                 float _TransScattering;
454                 float _TransDirect;
455                 float _TransAmbient;
456                 float _TransShadow;
457             #endif
458             #ifdef TESSELLATION_ON
459                 float _TessPhongStrength;
460                 float _TessValue;
461                 float _TessMin;
462                 float _TessMax;
463                 float _TessEdgeLength;
464                 float _TessMaxDisp;
465             #endif
466             CBUFFER_END
467             
468 
469             
470             VertexOutput VertexFunction( VertexInput v  )
471             {
472                 VertexOutput o = (VertexOutput)0;
473                 UNITY_SETUP_INSTANCE_ID(v);
474                 UNITY_TRANSFER_INSTANCE_ID(v, o);
475                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
476 
477                 
478                 #ifdef ASE_ABSOLUTE_VERTEX_POS
479                     float3 defaultVertexValue = v.vertex.xyz;
480                 #else
481                     float3 defaultVertexValue = float3(0, 0, 0);
482                 #endif
483                 float3 vertexValue = defaultVertexValue;
484                 #ifdef ASE_ABSOLUTE_VERTEX_POS
485                     v.vertex.xyz = vertexValue;
486                 #else
487                     v.vertex.xyz += vertexValue;
488                 #endif
489 
490                 v.ase_normal = v.ase_normal;
491                 float3 positionWS = TransformObjectToWorld( v.vertex.xyz );
492                 float4 positionCS = TransformWorldToHClip( positionWS );
493 
494                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
495                 o.worldPos = positionWS;
496                 #endif
497 
498                 #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) && defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
499                     VertexPositionInputs vertexInput = (VertexPositionInputs)0;
500                     vertexInput.positionWS = positionWS;
501                     vertexInput.positionCS = positionCS;
502                     o.shadowCoord = GetShadowCoord( vertexInput );
503                 #endif
504                 o.clipPos = positionCS;
505                 return o;
506             }
507 
508             #if defined(TESSELLATION_ON)
509             struct VertexControl
510             {
511                 float4 vertex : INTERNALTESSPOS;
512                 float3 ase_normal : NORMAL;
513                 
514                 UNITY_VERTEX_INPUT_INSTANCE_ID
515             };
516 
517             struct TessellationFactors
518             {
519                 float edge[3] : SV_TessFactor;
520                 float inside : SV_InsideTessFactor;
521             };
522 
523             VertexControl vert ( VertexInput v )
524             {
525                 VertexControl o;
526                 UNITY_SETUP_INSTANCE_ID(v);
527                 UNITY_TRANSFER_INSTANCE_ID(v, o);
528                 o.vertex = v.vertex;
529                 o.ase_normal = v.ase_normal;
530                 
531                 return o;
532             }
533 
534             TessellationFactors TessellationFunction (InputPatch<VertexControl,3> v)
535             {
536                 TessellationFactors o;
537                 float4 tf = 1;
538                 float tessValue = _TessValue; float tessMin = _TessMin; float tessMax = _TessMax;
539                 float edgeLength = _TessEdgeLength; float tessMaxDisp = _TessMaxDisp;
540                 #if defined(ASE_FIXED_TESSELLATION)
541                 tf = FixedTess( tessValue );
542                 #elif defined(ASE_DISTANCE_TESSELLATION)
543                 tf = DistanceBasedTess(v[0].vertex, v[1].vertex, v[2].vertex, tessValue, tessMin, tessMax, GetObjectToWorldMatrix(), _WorldSpaceCameraPos );
544                 #elif defined(ASE_LENGTH_TESSELLATION)
545                 tf = EdgeLengthBasedTess(v[0].vertex, v[1].vertex, v[2].vertex, edgeLength, GetObjectToWorldMatrix(), _WorldSpaceCameraPos, _ScreenParams );
546                 #elif defined(ASE_LENGTH_CULL_TESSELLATION)
547                 tf = EdgeLengthBasedTessCull(v[0].vertex, v[1].vertex, v[2].vertex, edgeLength, tessMaxDisp, GetObjectToWorldMatrix(), _WorldSpaceCameraPos, _ScreenParams, unity_CameraWorldClipPlanes );
548                 #endif
549                 o.edge[0] = tf.x; o.edge[1] = tf.y; o.edge[2] = tf.z; o.inside = tf.w;
550                 return o;
551             }
552 
553             [domain("tri")]
554             [partitioning("fractional_odd")]
555             [outputtopology("triangle_cw")]
556             [patchconstantfunc("TessellationFunction")]
557             [outputcontrolpoints(3)]
558             VertexControl HullFunction(InputPatch<VertexControl, 3> patch, uint id : SV_OutputControlPointID)
559             {
560                return patch[id];
561             }
562 
563             [domain("tri")]
564             VertexOutput DomainFunction(TessellationFactors factors, OutputPatch<VertexControl, 3> patch, float3 bary : SV_DomainLocation)
565             {
566                 VertexInput o = (VertexInput) 0;
567                 o.vertex = patch[0].vertex * bary.x + patch[1].vertex * bary.y + patch[2].vertex * bary.z;
568                 o.ase_normal = patch[0].ase_normal * bary.x + patch[1].ase_normal * bary.y + patch[2].ase_normal * bary.z;
569                 
570                 #if defined(ASE_PHONG_TESSELLATION)
571                 float3 pp[3];
572                 for (int i = 0; i < 3; ++i)
573                     pp[i] = o.vertex.xyz - patch[i].ase_normal * (dot(o.vertex.xyz, patch[i].ase_normal) - dot(patch[i].vertex.xyz, patch[i].ase_normal));
574                 float phongStrength = _TessPhongStrength;
575                 o.vertex.xyz = phongStrength * (pp[0]*bary.x + pp[1]*bary.y + pp[2]*bary.z) + (1.0f-phongStrength) * o.vertex.xyz;
576                 #endif
577                 UNITY_TRANSFER_INSTANCE_ID(patch[0], o);
578                 return VertexFunction(o);
579             }
580             #else
581             VertexOutput vert ( VertexInput v )
582             {
583                 return VertexFunction( v );
584             }
585             #endif
586 
587             half4 frag(VertexOutput IN  ) : SV_TARGET
588             {
589                 UNITY_SETUP_INSTANCE_ID(IN);
590                 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX( IN );
591 
592                 #if defined(ASE_NEEDS_FRAG_WORLD_POSITION)
593                 float3 WorldPosition = IN.worldPos;
594                 #endif
595                 float4 ShadowCoords = float4( 0, 0, 0, 0 );
596 
597                 #if defined(ASE_NEEDS_FRAG_SHADOWCOORDS)
598                     #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
599                         ShadowCoords = IN.shadowCoord;
600                     #elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
601                         ShadowCoords = TransformWorldToShadowCoord( WorldPosition );
602                     #endif
603                 #endif
604 
605                 
606                 float Alpha = 1;
607                 float AlphaClipThreshold = 0.5;
608 
609                 #ifdef _ALPHATEST_ON
610                     clip(Alpha - AlphaClipThreshold);
611                 #endif
612 
613                 #ifdef LOD_FADE_CROSSFADE
614                     LODDitheringTransition( IN.clipPos.xyz, unity_LODFade.x );
615                 #endif
616                 return 0;
617             }
618             ENDHLSL
619         }
620     }
621 }
View Code
  1 struct Attributes
  2 {
  3     float4 positionOS: POSITION;
  4     float2 uv        : TEXCOORD0;
  5     half2 lightmapUV : TEXCOORD1;
  6     float4 tangent   : TANGENT;
  7     float3 normal    : NORMAL;
  8 };
  9 
 10 struct Varyings
 11 {
 12     float4 positionHCS                   : SV_POSITION;
 13     float4 uv                            : TEXCOORD0;
 14     float3 posWS                         : TEXCOORD1;
 15     float3 eyeVec                        : TEXCOORD2;
 16     float4 tangentToWorldAndPackedData[3]: TEXCOORD3;
 17     half4  ambientOrLightmapUV           : TEXCOORD6;
 18     float3 normalWS                      : TEXCOORD7;
 19     float4 shadowCoord                   : TEXCOORD8;
 20     float4 lightmapUVOrVertexSH          : TEXCOORD9;
 21     float3 viewWS                        : TEXCOORD10;
 22     half4 fogFactorAndVertexLight        : TEXCOORD11;
 23     float4 screenPos                     : TEXCOORD12;
 24     //TODO
 25     //     UNITY_SHADOW_COORDS(6)
 26     //     UNITY_FOG_COORDS(7)
 27     // #else
 28     //     UNITY_LIGHTING_COORDS(6,7)
 29     //     UNITY_FOG_COORDS(8)
 30 };
 31 
 32 
 33 
 34 #include "UtilsInclude.hlsl"
 35 // #define DIRLIGHTMAP_COMBINED
 36 
 37 
 38 Varyings vert (Attributes IN, half FUR_OFFSET =0)
 39 {
 40     UNITY_SETUP_INSTANCE_ID(IN);
 41     Varyings OUT;
 42     OUT = (Varyings)0;
 43     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
 44     
 45     //Transform vertexPos by normal
 46     //短绒毛
 47     half3 direction = lerp(IN.normal, _Gravity * _GravityStrength + IN.normal * (1 - _GravityStrength), _FUR_OFFSET);
 48     //长毛
 49     // half3 direction = lerp(IN.normal, _Gravity * _GravityStrength + IN.normal, _FUR_OFFSET);
 50     IN.positionOS.xyz += direction * _FurLength * _FUR_OFFSET;
 51     OUT.posWS = TransformObjectToWorld(IN.positionOS.xyz);
 52     float3 positionWS = TransformObjectToWorld( IN.positionOS.xyz );
 53     float4 positionCS = TransformWorldToHClip( positionWS );
 54     OUT.screenPos = ComputeScreenPos(positionCS);
 55     
 56     OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
 57     OUT.uv.xy = TRANSFORM_TEX(IN.uv, _MainTex);
 58     OUT.viewWS = normalize( _WorldSpaceCameraPos - OUT.posWS);
 59     VertexNormalInputs normalInput = GetVertexNormalInputs( IN.normal, IN.tangent );
 60     half3 vertexLight = VertexLighting( positionWS, normalInput.normalWS );
 61     half fogFactor = ComputeFogFactor( positionCS.z );
 62     OUT.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
 63     OUT.eyeVec = NormalizePerVertexNormal(OUT.posWS.xyz - _WorldSpaceCameraPos);
 64     half3 normalWS = TransformObjectToWorldNormal(IN.normal);
 65     OUT.normalWS = normalWS;
 66     #ifdef _TANGENT_TO_WORLD
 67         float4 tangentWorld = float4(TransformObjectToWorldDir(IN.tangent.xyz), IN.tangent.w);
 68         float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWS, tangentWorld.xyz, tangentWorld.w);
 69         OUT.tangentToWorldAndPackedData[0].xyz = tangentToWorld[0];
 70         OUT.tangentToWorldAndPackedData[1].xyz = tangentToWorld[1];
 71         OUT.tangentToWorldAndPackedData[2].xyz = tangentToWorld[2];
 72     #else
 73         OUT.tangentToWorldAndPackedData[0].xyz = 0;
 74         OUT.tangentToWorldAndPackedData[1].xyz = 0;
 75         OUT.tangentToWorldAndPackedData[2].xyz = normalWS;
 76     #endif
 77 
 78     #ifdef _PARALLAXMAP
 79         TANGENT_SPACE_ROTATION;
 80         half3 viewDirForParallax = mul (rotation, ObjSpaceViewDir(IN.positionOS));
 81         OUT.tangentToWorldAndPackedData[0].w = viewDirForParallax.x;
 82         OUT.tangentToWorldAndPackedData[1].w = viewDirForParallax.y;
 83         OUT.tangentToWorldAndPackedData[2].w = viewDirForParallax.z;
 84     #endif
 85 
 86     VertexPositionInputs vertexInput = (VertexPositionInputs)0;
 87     vertexInput.positionWS = positionWS;
 88     vertexInput.positionCS = positionCS;
 89     OUTPUT_LIGHTMAP_UV(IN.lightmapUV, unity_LightmapST, OUT.lightmapUVOrVertexSH.xy);
 90     OUTPUT_SH(normalWS, OUT.lightmapUVOrVertexSH.xyz);
 91 
 92     OUT.ambientOrLightmapUV = VertexGIForward(IN, OUT.posWS, normalWS);
 93     //TODO Fog
 94     //TODO Shadow
 95     OUT.shadowCoord = GetShadowCoord( vertexInput );
 96     OUT.shadowCoord = TransformWorldToShadowCoord(positionWS);
 97 
 98     return OUT;
 99 }
100 
101 half4 frag (Varyings IN, half FUR_OFFSET = 0) : SV_Target
102 {
103     //Data
104     float3 Albedo = float3(0.5, 0.5, 0.5);
105     float Metallic = 0;
106     float3 Specular = 0.5;
107     float Smoothness = 0.5;
108     float Occlusion = 1;
109     float3 Emission = 0;
110     float Alpha = 1;
111     float3 BakedGI = 0;
112 
113     InputData inputData;
114     inputData.positionWS = IN.posWS;
115     inputData.viewDirectionWS = IN.viewWS;
116     inputData.shadowCoord = IN.shadowCoord;
117     inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
118     inputData.normalWS = IN.normalWS;
119     inputData.fogCoord = IN.fogFactorAndVertexLight.x;
120     inputData.bakedGI = 0;
121     #ifdef _GI_ON
122     inputData.bakedGI = SAMPLE_GI( IN.lightmapUVOrVertexSH.xy, IN.lightmapUVOrVertexSH.xyz, IN.normalWS );
123     #endif
124 
125     half4 color = UniversalFragmentPBR(
126     inputData, 
127     _Albedo, 
128     _Metallic, 
129     _Specular, 
130     _Smoothness, 
131     _Occlusion, 
132     _Emission, 
133     _Alpha);
134 
135     #ifdef _REFRACTION_ASE
136         float4 projScreenPos = ScreenPos / ScreenPos.w;
137         float3 refractionOffset = ( RefractionIndex - 1.0 ) * mul( UNITY_MATRIX_V, WorldNormal ).xyz * ( 1.0 - dot( WorldNormal, WorldViewDirection ) );
138         projScreenPos.xy += refractionOffset.xy;
139         float3 refraction = SHADERGRAPH_SAMPLE_SCENE_COLOR( projScreenPos ) * RefractionColor;
140         color.rgb = lerp( refraction, color.rgb, color.a );
141         color.a = 1;
142     #endif
143 
144     #ifdef ASE_FOG
145         #ifdef TERRAIN_SPLAT_ADDPASS
146             color.rgb = MixFogColor(color.rgb, half3( 0, 0, 0 ), IN.fogFactorAndVertexLight.x );
147         #else
148             color.rgb = MixFog(color.rgb, IN.fogFactorAndVertexLight.x);
149         #endif
150     #endif
151 
152     //
153     //Dither
154     //UnityApplyDitherCrossFade(IN.positionHCS.xy);
155     half facing = dot(-IN.eyeVec, IN.tangentToWorldAndPackedData[2].xyz);
156     facing = saturate(ceil(facing)) * 2 - 1;
157 
158     FRAGMENT_SETUP(s)
159     UNITY_SETUP_INSTANCE_ID(IN);
160     UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);
161 
162     Light mainLight = GetMainLight (IN.shadowCoord);
163     half occlusion = CalOcclusion(IN.uv.xy);
164 
165     // #ifdef _GI_ON
166     // inputData.bakedGI = SAMPLE_GI(IN.lightmapUVOrVertexSH.xy, IN.lightmapUVOrVertexSH.xyz, IN.normalWS);
167     // #endif
168     //PBR
169     BRDFData brdfData;
170     half3 albedo = 0.5;
171     half3 specular = .5;
172     half brdfAlpha = 1;
173     InitializeBRDFData(albedo,0,specular,0.5, brdfAlpha, brdfData);
174     #ifdef _RECEIVE_SHADOWS
175     half lightAttenuation = mainLight.distanceAttenuation * mainLight.shadowAttenuation;
176     #else
177     half lightAttenuation = 1;
178     #endif
179     half NdotL = saturate(dot(inputData.normalWS, mainLight.direction));
180     half3 radiance = mainLight.color * (lightAttenuation * NdotL);
181     // half3 GIcolor = GlobalIllumination(brdfData, inputData.bakedGI, occlusion, inputData.normalWS, inputData.viewDirectionWS);
182     // half3 BRDFColor = LightingPhysicallyBased(brdfData, mainLight, inputData.normalWS, inputData.viewDirectionWS);
183     //
184 
185     half4 c = FABRIC_BRDF_PBS(s.diffColor, s.specColor, s.oneMinusReflectivity, s.smoothness, s.normalWorld, -s.eyeVec, mainLight, inputData, lightAttenuation);
186 
187     c.rgb += CalEmission(IN.uv.xy);
188 
189     //UNITY_APPLY_FOG(i.fogCoord, c.rgb);
190     // half alpha = tex2D(_LayerTex, TRANSFORM_TEX(IN.uv.xy, _LayerTex)).r;
191     float2 uvoffset = tex2D(_FlowMap, IN.uv.xy).rg*2-1;
192     // return tex2D(_FlowMap, IN.uv);
193     half alpha = tex2D(_LayerTex, TRANSFORM_TEX(IN.uv.xy, _LayerTex) + _UVOffset * uvoffset * _FUR_OFFSET).r;
194     alpha = step(lerp(0, _CutoffEnd, _FUR_OFFSET), alpha);
195     c.a = 1 - _FUR_OFFSET * _FUR_OFFSET;
196     c.a += dot(-s.eyeVec, s.normalWorld) - _EdgeFade;
197     c.a = max(0, c.a);
198     c.a *= alpha;
199     c = half4(c.rgb * lerp(lerp(_ShadowColor.rgb, 1, _FUR_OFFSET), 1, _ShadowLerp), c.a);
200     // float3 mainAtten = mainLight.color * mainLight.distanceAttenuation;
201     // mainAtten = lerp( mainAtten, mainAtten * mainLight.shadowAttenuation, shadow );
202 
203     // return half4(GIcolor+BRDFColor,1);
204     // return half4(mainLight.color * mainLight.distanceAttenuation,1);
205     // #ifdef MAIN_LIGHT_CALCULATE_SHADOWS
206     // return 1;
207     // #else 
208     // return 0;
209     
210     // #endif
211     return c;
212 }
213 Varyings vert_LayerBase(Attributes IN)
214 {
215     return vert(IN, 0);
216 }
217 Varyings vert_Layer(Attributes IN)
218 {
219     return vert(IN, .1);
220 }
221 half4 frag_LayerBase(Varyings IN) : SV_Target
222 {
223     return frag(IN, .0);
224 }
225 half4 frag_Layer(Varyings IN) : SV_Target
226 {
227     return frag(IN, .1);
228 }
View Code

效果:

 转载请注明出处:https://www.cnblogs.com/jietian331/p/17330302.html

 

#define DEBUGAREARECT
using System;
using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
using GameLogic;
using GameLogic.TimeOfDay;
using UnityEngine;
using UnityEngine.Rendering;
using Color = UnityEngine.Color;
using Vector2Int = TrueSync.Vector2Int;
using Vector3 = UnityEngine.Vector3;

namespace Gameplay
{
    partial class HomeMap
    {
        public const string HoledSandName = "Env_Home_Terrain_06";
        public const string BuildingLightTransName = "Light";
        private const string HighlightLinesRootName = "HighlightLine";
        private const string AreaLinesRootName = "AreaLine";

        private List<Transform> m_StaticBuildingsLight;

        /// <summary>
        /// 所有静态灯
        /// </summary>
        List<Transform> StaticBuildingsLight
        {
            get
            {
                if (m_StaticBuildingsLight == null)
                {
                    m_StaticBuildingsLight = new();
                    GameObject objBuildingsRoot = GameObject.Find("Root/Scene/Building");
                    if (objBuildingsRoot)
                    {
                        foreach (Transform child in objBuildingsRoot.transform)
                        {
                            Transform light = child.Find(BuildingLightTransName);
                            if (light)
                                m_StaticBuildingsLight.Add(light);
                        }
                    }
                }

                return m_StaticBuildingsLight;
            }
        }

        #region 区域高亮线框

        /// <summary>显示区域高亮线框,如选中时</summary>
        public void ShowHighlightLines(HomeAreaEntity area)
        {
            if (area == null)
            {
                return;
            }

            Transform root = GetOrCreateRootTrans(HighlightLinesRootName);
            root.gameObject.SetActive(true);
            root.transform.position = area.ParentTransform.position;

            List<Shapes.Line> lines = new();
            foreach (Transform c in root)
            {
                lines.Add(c.GetComponent<Shapes.Line>());
            }

            if (lines.Count > 3)
            {
                area.SyncLinesBorders(lines);
            }
        }

        /// <summary>隐藏区域高亮线框</summary>
        public void HideHighlightLines()
        {
            Transform root = GetOrCreateRootTrans(HighlightLinesRootName);
            root.gameObject.SetActive(false);
        }

        private async UniTask LoadHighlightLines()
        {
            Transform root = GetOrCreateRootTrans(HighlightLinesRootName);
            root.gameObject.SetActive(false);
            if (root.childCount > 3)
                return;

            var rectLinePrefab = await GameModule.Resource.LoadAssetAsync<GameObject>("vfx_env_rectline_highlight");
            for (int i = 0; i < 4; i++)
            {
                Shapes.Line line = CreateLine(rectLinePrefab, root);
                line.name = $"HightlightAreaRectLine_{i}";
                line.ZTest = CompareFunction.Always;
            }
        }

        Shapes.Line CreateLine(GameObject rectLinePrefab, Transform parent)
        {
            var edgeGo = UnityEngine.Object.Instantiate(rectLinePrefab, parent, false);
            edgeGo.transform.localPosition = Vector3.zero;
            edgeGo.transform.localRotation = Quaternion.identity;
            edgeGo.transform.localScale = Vector3.one;

            var line = edgeGo.GetComponent<Shapes.Line>();
            if (line == null)
                line = edgeGo.AddComponent<Shapes.Line>();

            return line;
        }

        #endregion

        #region 区域常驻边界线框 & 栅栏

        class LineData
        {
            public Vector2Int Start;
            public Vector2Int End;

            public bool IsHorizontal => Start.y == End.y;

            public LineData(Vector2Int start, Vector2Int end)
            {
                if (start.y == end.y) //是横线
                {
                    Start = new Vector2Int(Mathf.Min(start.x, end.x), start.y);
                    End = new Vector2Int(Mathf.Max(start.x, end.x), start.y);
                }
                else
                {
                    Start = new Vector2Int(start.x, Mathf.Min(start.y, end.y));
                    End = new Vector2Int(start.x, Mathf.Max(start.y, end.y));
                }
            }
        }

        public void RefreshLinesAndFences()
        {
            RefreshLinesAndFencesAsync().Forget();
        }

        Transform GetOrCreateRootTrans(string name)
        {
            Transform root = EntityRenderPool.instance.InstanceRoot;
            Transform parent = root.Find(name);
            if (!parent)
            {
                parent = new GameObject(name).transform;
                parent.transform.SetParent(root, false);
                parent.transform.localRotation = Quaternion.identity;
                parent.transform.localScale = Vector3.one;
                parent.transform.localPosition = new Vector3(0f, 0.02f, 0f);

                int layer = LayerMask.NameToLayer(LayerHelper.HideLayer);
                HomeAreaEntity.SetLayerRecursively(parent.gameObject, layer);
            }

            return parent;
        }

        public List<Shapes.Line> GetAllAreaLines()
        {
            List<Shapes.Line> list = new();
            Transform parent = GetOrCreateRootTrans(AreaLinesRootName);
            foreach (Transform c in parent)
            {
                if (c.gameObject.activeSelf)
                {
                    Shapes.Line line = c.GetComponent<Shapes.Line>();
                    if (line)
                    {
                        list.Add(line);
                    }
                }
            }

            return list;
        }

        private async UniTask RefreshLinesAndFencesAsync()
        {
            Transform parent = GetOrCreateRootTrans(AreaLinesRootName);
            parent.gameObject.SetActive(true);
            foreach (Transform c in parent)
            {
                c.gameObject.SetActive(false);
            }

            // 收集线段
            List<LineData> lines = CollectBorderLines(out List<LineData> fenceItems);

            // 渲染线段
            GameObject rectLinePrefab = null;
            for (int i = 0; i < lines.Count; i++)
            {
                var lineData = lines[i];

                string transName = $"AreaLine_{i}";
                Transform transLine = parent.Find(transName);
                Shapes.Line line;
                if (transLine)
                {
                    line = transLine.GetComponent<Shapes.Line>();
                }
                else
                {
                    if (rectLinePrefab == null)
                        rectLinePrefab = await GameModule.Resource.LoadAssetAsync<GameObject>("vfx_env_rectline_normal");
                    line = CreateLine(rectLinePrefab, parent);
                }

                line.name = transName;
                line.gameObject.SetActive(true);
                line.Start = lineData.Start.ToUnityPosition() + new Vector3(0, 0.2f);
                line.End = lineData.End.ToUnityPosition() + new Vector3(0, 0.2f);
            }

            TimeOfDay.Instance?.SetMapNormalLineColor();

            // 渲染栅栏
            List<LineData> littleFenceItems = new();
            List<LineData> largeFenceItems = new();
            foreach (var fenceItem in fenceItems)
            {
                Vector3 start = fenceItem.Start.ToUnityPosition();
                Vector3 end = fenceItem.End.ToUnityPosition();
                Vector3 dir = start - end;
                float length = dir.magnitude;
                bool isLittle = length < 13; // 10米和15米两种规格
                if (isLittle)
                {
                    littleFenceItems.Add(fenceItem);
                }
                else
                {
                    largeFenceItems.Add(fenceItem);
                }
            }

            await CreateFenceObjects(littleFenceItems, "Env_Home_sundries_13");
            await CreateFenceObjects(largeFenceItems, "Env_Home_sundries_14");
        }

        private async UniTask CreateFenceObjects(List<LineData> fenceItems, string prefabName)
        {
            Transform parent = GetOrCreateRootTrans("Fences");
            parent.gameObject.SetActive(true);
            foreach (Transform c in parent)
            {
                if (c.name.StartsWith(prefabName))
                    c.gameObject.SetActive(false);
            }

            GameObject fencePrefab = null;
            for (int i = 0; i < fenceItems.Count; i++)
            {
                var fenceItem = fenceItems[i];
                Vector3 start = fenceItem.Start.ToUnityPosition();
                Vector3 end = fenceItem.End.ToUnityPosition();
                Vector3 dir = start - end;
                Vector3 center = (start + end) / 2f;

                string transName = $"{prefabName}_{i}";
                Transform fencerTrans = parent.Find(transName);
                if (!fencerTrans)
                {
                    if (fencePrefab == null)
                        fencePrefab = await GameModule.Resource.LoadAssetAsync<GameObject>(prefabName);
                    fencerTrans = UnityEngine.Object.Instantiate(fencePrefab, parent).transform;
                }

                fencerTrans.gameObject.SetActive(true);
                fencerTrans.name = $"{prefabName}_{i}";
                fencerTrans.transform.position = center;
                fencerTrans.transform.rotation = Quaternion.Euler(0, 90, 0) * Quaternion.LookRotation(dir, Vector3.up);
                fencerTrans.transform.localScale = Vector3.one;
            }
        }

        List<LineData> CollectBorderLines(out List<LineData> fenceItems)
        {
            List<LineData> lineDatas = new();
            fenceItems = new();
            Dictionary<long, HomeAreaEntity> dicAreas = new();
            foreach (var pairBuildigCell in _buildingCells)
            {
                foreach (var id in pairBuildigCell.Value)
                {
                    if (dicAreas.ContainsKey(id))
                    {
                        continue;
                    }

                    var areaEntity = Scene.GetEntity<HomeAreaEntity>(id);
                    if (areaEntity == null)
                    {
                        continue;
                    }

                    dicAreas.Add(id, areaEntity);

                    var areaData = GameModule.DataCenter.buildingDataCache.Areas[id];

                    //sb.AppendLine($"id:{id} pos:{areaEntity.Position} size:{areaEntity.GridSize} renderPos:{areaEntity.RenderPosition}");

                    // debug
#if DEBUGAREARECT && UNITY_EDITOR
                    DebugRectGizmos debugRectGizmos = areaEntity.ParentTransform.gameObject.GetComponent<DebugRectGizmos>();
                    if (debugRectGizmos == null)
                        debugRectGizmos = areaEntity.ParentTransform.gameObject.AddComponent<DebugRectGizmos>();
                    debugRectGizmos.GizmosLabel = $"id:{id} rect:{areaEntity.Position.x},{areaEntity.Position.z} {areaEntity.GridSize} state:{areaData.State}";
                    debugRectGizmos.SquareSize = new Vector2(areaEntity.GridSize.x, areaEntity.GridSize.y);
#endif

                    if (areaData.State == MapEntityState.Normal)
                    {
                        continue;
                    }

                    CalcAreaBorderLines(areaEntity, ref lineDatas, ref fenceItems);
                }
            }

            // 合并,优化线段
            List<LineData> newLines = OptimizeLines(lineDatas);
            return newLines;
        }

        // 合并,优化线段
        List<LineData> OptimizeLines(List<LineData> oldLines)
        {
            List<List<LineData>> optimizedLines = new();
            foreach (var oldLine in oldLines)
            {
                bool isSameLine = false;
                bool isHorizontal = oldLine.IsHorizontal;
                foreach (var listLines in optimizedLines)
                {
                    if (listLines[0].IsHorizontal != isHorizontal)
                    {
                        continue;
                    }

                    if (isHorizontal && oldLine.Start.y == listLines[0].Start.y)
                    {
                        if (oldLine.Start.x == listLines.LastOrDefault().End.x)
                        {
                            listLines.Add(oldLine);
                            isSameLine = true;
                        }
                        else if (oldLine.End.x == listLines.FirstOrDefault().Start.x)
                        {
                            listLines.Insert(0, oldLine);
                            isSameLine = true;
                        }
                    }
                    else if (oldLine.Start.x == listLines[0].Start.x)
                    {
                        if (oldLine.Start.y == listLines.LastOrDefault().End.y)
                        {
                            listLines.Add(oldLine);
                            isSameLine = true;
                        }
                        else if (oldLine.End.y == listLines.FirstOrDefault().Start.y)
                        {
                            listLines.Insert(0, oldLine);
                            isSameLine = true;
                        }
                    }
                }

                if (!isSameLine)
                {
                    List<LineData> listLines = new();
                    listLines.Add(oldLine);
                    optimizedLines.Add(listLines);
                }
            }

            List<LineData> lines = new();
            foreach (var listLines in optimizedLines)
            {
                Vector2Int start = listLines.FirstOrDefault().Start;
                Vector2Int end = listLines.LastOrDefault().End;
                LineData lineData = new(start, end);
                lines.Add(lineData);
            }

            return lines;
        }

        void CalcAreaBorderLines(HomeAreaEntity areaEntity, ref List<LineData> lineDatas, ref List<LineData> fenceItems)
        {
            int posX = (int)areaEntity.Position.x;
            int posZ = (int)areaEntity.Position.z;
            int halfWidth = areaEntity.GridSize.x / 2;
            int halfHeight = areaEntity.GridSize.y / 2;
            Vector2Int topPos = new Vector2Int(posX + halfWidth, posZ + areaEntity.GridSize.y + 5);
            Vector2Int bottomPos = new Vector2Int(posX + halfWidth, posZ - 5);
            Vector2Int leftPos = new Vector2Int(posX - 5, posZ + halfHeight);
            Vector2Int rightPos = new Vector2Int(posX + areaEntity.GridSize.x + 5, posZ + halfHeight);

            var topArea = GetAreaAt(topPos);
            var bottomArea = GetAreaAt(bottomPos);
            var leftArea = GetAreaAt(leftPos);
            var rightArea = GetAreaAt(rightPos);

            Vector2Int posTopLeft = new Vector2Int(posX, posZ + areaEntity.GridSize.y);
            Vector2Int posTopRight = new Vector2Int(posX + areaEntity.GridSize.x, posZ + areaEntity.GridSize.y);
            Vector2Int posBottomLeft = new Vector2Int(posX, posZ);
            Vector2Int posBottomRight = new Vector2Int(posX + areaEntity.GridSize.x, posZ);

            //上
            if (topArea != null)
            {
                var topAreaData = GameModule.DataCenter.buildingDataCache.Areas[topArea.Id];
                if (topAreaData.State == MapEntityState.Normal)
                {
                    LineData lineData = new LineData(posTopLeft, posTopRight);
                    lineDatas.Add(lineData);
                    fenceItems.Add(lineData);
                }
            }
            else
            {
                LineData lineData = new LineData(posTopLeft, posTopRight);
                lineDatas.Add(lineData);

                // 悬崖边上的那条边上必有栅栏
                if (posTopLeft.y > 3)
                {
                    fenceItems.Add(lineData);
                }
            }

            //下
            if (bottomArea != null)
            {
                var bottomAreaData = GameModule.DataCenter.buildingDataCache.Areas[bottomArea.Id];
                if (bottomAreaData.State == MapEntityState.Normal)
                {
                    LineData lineData = new LineData(posBottomLeft, posBottomRight);
                    lineDatas.Add(lineData);
                    fenceItems.Add(lineData);
                }
            }
            else
            {
                LineData lineData = new LineData(posBottomLeft, posBottomRight);
                lineDatas.Add(lineData);
            }

            //左
            if (leftArea != null)
            {
                var leftAreaData = GameModule.DataCenter.buildingDataCache.Areas[leftArea.Id];
                if (leftAreaData.State == MapEntityState.Normal)
                {
                    LineData lineData = new LineData(posBottomLeft, posTopLeft);
                    lineDatas.Add(lineData);
                    fenceItems.Add(lineData);
                }
            }
            else
            {
                lineDatas.Add(new LineData(posBottomLeft, posTopLeft));
            }

            //右
            if (rightArea != null)
            {
                var rightAreaData = GameModule.DataCenter.buildingDataCache.Areas[rightArea.Id];
                if (rightAreaData.State == MapEntityState.Normal)
                {
                    LineData lineData = new LineData(posBottomRight, posTopRight);
                    lineDatas.Add(lineData);
                    fenceItems.Add(lineData);
                }
            }
            else
            {
                lineDatas.Add(new LineData(posBottomRight, posTopRight));
            }
        }

        public static void SetNormalLineColor(Color color)
        {
            if (GameModule.Home == null || GameModule.Home.HomeEngine == null || GameModule.Home.HomeEngine.HomeScene == null ||
                GameModule.Home.HomeEngine.HomeScene.HomeMap == null)
            {
                return;
            }

            var lines = GameModule.Home.HomeEngine.HomeScene.HomeMap.GetAllAreaLines();
            foreach (var l in lines)
            {
                if (l != null)
                    l.Color = color;
            }
        }

        #endregion

        #region 沙丘挖洞

        Material GetSandMaterialFromScene(out GameObject sandObj)
        {
            string sandPath = $"Root/Scene/Tarrain/{HoledSandName}";
            sandObj = GameObject.Find(sandPath);
            if (!sandObj)
            {
                Common.Logger.Error($"Cann't find sand object, path:{sandPath}");
                return null;
            }

            Material matSand = sandObj.GetComponent<Renderer>().sharedMaterial;
            return matSand;
        }

        Vector4 GetSandAreaUVRect(GameLogic.Area area)
        {
            Rect sandRect = new Rect(-59.073f, -70.486f, 134f, 92f);
            float rectXMin = (area.Position.Value.X - sandRect.x) / sandRect.width;
            float rectXMax = rectXMin + area.Size.X / sandRect.width;
            float rectYMin = (area.Position.Value.Y - sandRect.y) / sandRect.height;
            float rectYMax = rectYMin + area.Size.Y / sandRect.height;
            float rectOffset = 0.01f;

            rectXMin -= rectOffset;
            rectXMax += rectOffset;
            rectYMin -= rectOffset;
            rectYMax += rectOffset;

            Vector4 rect = new Vector4(rectXMin, rectYMin, rectXMax - rectXMin, rectYMax - rectYMin);
            return rect;
        }

        /// <summary>刷新挖沙遮罩图,刷新区域线段和栅栏</summary>
        /// <param name="extraAreaId">需要额外作为"已挖开"纳入遮罩的地块 Uuid(0 = 无),
        /// 用于动画刚播完但服务端尚未确认 Normal 时,避免地块短暂复原。</param>
        public void RefreshSandHoleAndFences()
        {
            RefreshLinesAndFences();

            HideHighlightLines();

            Material matSand = GetSandMaterialFromScene(out GameObject sandObj);
            if (!matSand)
                return;

            sandObj.SetActive(true);

            // 生成遮罩图
            var areas = GameModule.DataCenter.buildingDataCache.Areas;

            Material mat = GameModule.Resource.LoadAsset<Material>("SandHoleMaskMapGenerator");

            int size = 1024;
            RenderTexture rt1 = RenderTexture.GetTemporary(size, size);
            RenderTexture rt2 = RenderTexture.GetTemporary(size, size);
            bool useRt1 = true;
            bool firstCombine = true;
            float rectOffset = 0.02f;

            foreach (var area in areas.Values)
            {
                if (!area.Position.HasValue)
                    continue;
                bool hasHole = area.State == MapEntityState.Normal || area.IsUnlockPendingConfirm;
                if (!hasHole)
                    continue;

                Vector4 rect = GetSandAreaUVRect(area);
                mat.mainTexture = firstCombine ? null : (useRt1 ? rt1 : rt2);
                mat.SetVector(ShaderProperty._Rect, rect);
                RenderTexture dest = useRt1 ? rt2 : rt1;
                Graphics.Blit(null, dest, mat);
                useRt1 = !useRt1;
                firstCombine = false;
            }

            // 保存成 texture
            RenderTexture.active = useRt1 ? rt1 : rt2;
            Texture2D texture2D = new Texture2D(size, size, TextureFormat.RGB24, false);
            texture2D.name = "SandHoleMask";
            texture2D.ReadPixels(new Rect(0, 0, size, size), 0, 0);
            texture2D.Apply();
            RenderTexture.active = null;

            RenderTexture.ReleaseTemporary(rt1);
            RenderTexture.ReleaseTemporary(rt2);

            // 遮罩图设置到沙子材质
            matSand.SetTexture(ShaderProperty._HoleRectMap, texture2D);
        }

        /// <summary>
        /// 从中心点往外溶解的挖沙动画
        /// </summary>
        /// <param name="area">要播放动画的区域</param>
        /// <param name="startTime">动画已经历时间(断点续播起点)</param>
        /// <param name="animLength">动画总时长</param>
        /// <param name="onPlayFinished">动画播完回调(可选)</param>
        public async UniTaskVoid PlayAreaHoleAnim(GameLogic.Area area, float startTime, float animLength, Action onPlayFinished = null)
        {
            Material matSand = GetSandMaterialFromScene(out GameObject sandObj);
            if (!matSand)
                return;

            sandObj.SetActive(true);

            Material matAnimHole = GameModule.Resource.LoadAsset<Material>("SandAreaAnimHole");

            Vector4 rect = GetSandAreaUVRect(area);
            RenderTexture rt = RenderTexture.GetTemporary(256, 256);
            matSand.EnableKeyword("_USEANOTHERHOLERECTMAP");
            matSand.SetTexture(ShaderProperty._AnotherHoleRectMap, rt);
            matSand.SetVector(ShaderProperty._AnotherHoleRect, rect);

            float timer = startTime;
            while (timer <= animLength)
            {
                float progress = Mathf.Min(1, timer / animLength);
                matAnimHole.SetFloat(ShaderProperty._Progress, progress);
                Graphics.Blit(null, rt, matAnimHole);

                timer += Time.deltaTime;

                await UniTask.Yield();
            }

            // 先更新静态遮罩(_HoleRectMap),再关掉动态 keyword。
            // 必须保证 _HoleRectMap 已包含本区域的洞,DisableKeyword 切换后才不会出现沙子闪回。
            onPlayFinished?.Invoke();

            matSand.DisableKeyword("_USEANOTHERHOLERECTMAP");
            RenderTexture.ReleaseTemporary(rt);
        }

        /*
        // 基于序列帧动画的挖沙动画
        public async UniTaskVoid PlayAreaHoleAnim(GameLogic.Area area, float animLength, Action onPlayFinished)
        {
            Material matSand = GetSandMaterialFromScene();
            if (!matSand)
                return;

            Material matAnimHole = GameModule.Resource.LoadAsset<Material>("SandAreaAnimHole");
            int shaderId_CurFrame = Shader.PropertyToID("_CurFrame");
            int shaderId_hAmount = Shader.PropertyToID("_HorizontalAmount");
            int shaderId_vAmount = Shader.PropertyToID("_VerticalAmount");
            int hAmount = (int)matAnimHole.GetFloat(shaderId_hAmount);
            int vAmount = (int)matAnimHole.GetFloat(shaderId_vAmount);
            int totalFrame = hAmount * vAmount;

            Vector4 rect = GetSandAreaUVRect(area);
            RenderTexture rt = RenderTexture.GetTemporary(256, 256);
            matSand.EnableKeyword("_USEANOTHERHOLERECTMAP");
            matSand.SetTexture("_AnotherHoleRectMap", rt);
            matSand.SetVector("_AnotherHoleRect", rect);

            float timer = 0;
            int curFrame = 0;
            float interval = animLength / totalFrame;
            while (curFrame <= totalFrame)
            {
                timer -= Time.deltaTime;
                if (timer < 0)
                {
                    timer = interval;
                    matAnimHole.SetFloat(shaderId_CurFrame, curFrame);
                    Graphics.Blit(null, rt, matAnimHole);
                    ++curFrame;
                }

                await UniTask.Yield();
            }

            matSand.DisableKeyword("_USEANOTHERHOLERECTMAP");
            RenderTexture.ReleaseTemporary(rt);

            onPlayFinished?.Invoke();
        }
        */

        #endregion

        #region 建筑灯光

        /// <summary>当摄像机移动,或者fov发生变化,则</summary>
        private void OnCameraUpdate(Camera camera)
        {
            if (_buildingEntities == null)
            {
                return;
            }

            if (GameModule.DataCenter.WorldStateDataCache.DayPhaseId != 3)
            {
                return;
            }

            if (camera.fieldOfView < 20)
            {
                foreach (var pair in _buildingEntities)
                {
                    if (pair.Value != null && pair.Value.BuildingRender != null && pair.Value.BuildingRender.HasGameObject && pair.Value.LightRoot)
                    {
                        bool isVisible = IsBuildingRendered(pair.Value.BuildingRender.Transform);
                        pair.Value.LightRoot.gameObject.SetActive(isVisible);
                    }
                }

                for (int i = 0; i < StaticBuildingsLight.Count; i++)
                {
                    var transLight = StaticBuildingsLight[i];
                    if (transLight)
                    {
                        bool isVisible = IsBuildingRendered(transLight.gameObject.transform);
                        transLight.gameObject.SetActive(isVisible);
                    }
                }
            }
            else
            {
                HideAllBuildingLight();
            }
        }

        bool IsBuildingRendered(Transform transform)
        {
            if (!transform)
            {
                return false;
            }

            Vector3 viewportPoint = Camera.main.WorldToViewportPoint(transform.position);
            return viewportPoint.x > 0f && viewportPoint.x < 1f && viewportPoint.y > 0f && viewportPoint.y < 1f;
            /*
            Renderer[] renderers = buildingObj.GetComponentsInChildren<Renderer>();
            foreach (var r in renderers)
            {
                if (r.isVisible)
                    return true;
            }

            return false;
            */
        }

        void HideAllBuildingLight()
        {
            if (_buildingEntities != null)
            {
                foreach (var pair in _buildingEntities)
                {
                    if (pair.Value != null && pair.Value.BuildingRender != null && pair.Value.LightRoot)
                        pair.Value.LightRoot.gameObject.SetActive(false);
                }
            }

            foreach (var staticBuildingLight in StaticBuildingsLight)
            {
                if (staticBuildingLight)
                    staticBuildingLight.gameObject.SetActive(false);
            }
        }

        private void OnWorldStateSync(int oldDayPhaseId, int newDayPhaseId, int oldWeatherId, int newWeatherId)
        {
            // 当晚上过去,则关闭所有建筑灯光
            if (newDayPhaseId != 3)
            {
                HideAllBuildingLight();
            }
        }

        #endregion
    }
}
View Code

 

Shader "Omnee/TextMeshPro/Font Outline And Shadow"
{
    Properties
    {
        [HDR]_FaceColor ("Face Color", Color) = (1,1,1,1)

        [Header(Outline)]
        [Toggle] _OutlineOn("开启描边", float) = 1
        [HDR]_OutlineColor ("描边颜色", Color) = (0,0,0,1)
        _OutlineWidth ("描边大小", Range(0,1)) = 0

        [Header(Shadow)]
        [HDR]_UnderlayColor ("阴影颜色", Color) = (0,0,0,.5)
        _UnderlayOffsetX ("阴影位置x", Range(-2,2)) = 0
        _UnderlayOffsetY ("阴影位置y", Range(-2,2)) = 0
        _UnderlayWidth ("阴影大小", Range(0,1)) = 0

        [Header(Other)]
        _WeightNormal ("Weight Normal", float) = 0
        _WeightBold ("Weight Bold", float) = .5

        _ShaderFlags ("Flags", float) = 0
        _ScaleRatioA ("Scale RatioA", float) = 1
        _ScaleRatioB ("Scale RatioB", float) = 1
        _ScaleRatioC ("Scale RatioC", float) = 1

        _MainTex ("Font Atlas", 2D) = "white" {}
        _TextureWidth ("Texture Width", float) = 512
        _TextureHeight ("Texture Height", float) = 512
        _GradientScale ("Gradient Scale", float) = 5
        _ScaleX ("Scale X", float) = 1
        _ScaleY ("Scale Y", float) = 1
        _PerspectiveFilter ("Perspective Correction", Range(0, 1)) = 0.875
        _Sharpness ("Sharpness", Range(-1,1)) = 0

        _VertexOffsetX ("Vertex OffsetX", float) = 0
        _VertexOffsetY ("Vertex OffsetY", float) = 0

        _ClipRect ("Clip Rect", vector) = (-32767, -32767, 32767, 32767)
        _MaskSoftnessX ("Mask SoftnessX", float) = 0
        _MaskSoftnessY ("Mask SoftnessY", float) = 0

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _CullMode ("Cull Mode", Float) = 0
        _ColorMask ("Color Mask", Float) = 15
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
        }


        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull [_CullMode]
        ZWrite Off
        Lighting Off
        Fog
        {
            Mode Off
        }
        ZTest [unity_GUIZTestMode]
        Blend One OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
            CGPROGRAM
            #pragma vertex VertShader
            #pragma fragment PixShader

            #pragma multi_compile __ UNITY_UI_CLIP_RECT
            #pragma multi_compile __ UNITY_UI_ALPHACLIP

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            // UI Editable properties
            uniform sampler2D _FaceTex; // Alpha : Signed Distance
            uniform float _FaceUVSpeedX;
            uniform float _FaceUVSpeedY;
            uniform fixed4 _FaceColor; // RGBA : Color + Opacity

            uniform sampler2D _OutlineTex; // RGBA : Color + Opacity
            uniform float _OutlineUVSpeedX;
            uniform float _OutlineUVSpeedY;
            uniform fixed4 _OutlineColor; // RGBA : Color + Opacity
            uniform float _OutlineWidth; // v[ 0, 1]
            float _UnderlayWidth;

            uniform float _Bevel; // v[ 0, 1]
            uniform float _BevelOffset; // v[-1, 1]
            uniform float _BevelWidth; // v[-1, 1]
            uniform float _BevelClamp; // v[ 0, 1]
            uniform float _BevelRoundness; // v[ 0, 1]

            uniform sampler2D _BumpMap; // Normal map
            uniform float _BumpOutline; // v[ 0, 1]
            uniform float _BumpFace; // v[ 0, 1]

            uniform samplerCUBE _Cube; // Cube / sphere map
            uniform fixed4 _ReflectFaceColor; // RGB intensity
            uniform fixed4 _ReflectOutlineColor;
            //uniform float        _EnvTiltX;                    // v[-1, 1]
            //uniform float        _EnvTiltY;                    // v[-1, 1]
            uniform float3 _EnvMatrixRotation;
            uniform float4x4 _EnvMatrix;

            uniform fixed4 _SpecularColor; // RGB intensity
            uniform float _LightAngle; // v[ 0,Tau]
            uniform float _SpecularPower; // v[ 0, 1]
            uniform float _Reflectivity; // v[ 5, 15]
            uniform float _Diffuse; // v[ 0, 1]
            uniform float _Ambient; // v[ 0, 1]

            uniform fixed4 _UnderlayColor; // RGBA : Color + Opacity
            uniform float _UnderlayOffsetX; // v[-1, 1]
            uniform float _UnderlayOffsetY; // v[-1, 1]

            uniform fixed4 _GlowColor; // RGBA : Color + Intesity
            uniform float _GlowOffset; // v[-1, 1]
            uniform float _GlowOuter; // v[ 0, 1]
            uniform float _GlowInner; // v[ 0, 1]
            uniform float _GlowPower; // v[ 1, 1/(1+4*4)]

            // API Editable properties
            uniform float _ShaderFlags;
            uniform float _WeightNormal;
            uniform float _WeightBold;

            uniform float _ScaleRatioA;
            uniform float _ScaleRatioB;
            uniform float _ScaleRatioC;

            uniform float _VertexOffsetX;
            uniform float _VertexOffsetY;

            //uniform float        _UseClipRect;
            uniform float _MaskID;
            uniform sampler2D _MaskTex;
            uniform float4 _MaskCoord;
            uniform float4 _ClipRect; // bottom left(x,y) : top right(z,w)
            //uniform float        _MaskWipeControl;
            //uniform float        _MaskEdgeSoftness;
            //uniform fixed4        _MaskEdgeColor;
            //uniform bool        _MaskInverse;

            uniform float _MaskSoftnessX;
            uniform float _MaskSoftnessY;

            // Font Atlas properties
            uniform sampler2D _MainTex;
            uniform float _TextureWidth;
            uniform float _TextureHeight;
            uniform float _GradientScale;
            uniform float _ScaleX;
            uniform float _ScaleY;
            uniform float _PerspectiveFilter;
            uniform float _Sharpness;


            struct vertex_t
            {
                UNITY_VERTEX_INPUT_INSTANCE_ID
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                fixed4 color : COLOR;
                float2 texcoord0 : TEXCOORD0;
                float2 texcoord1 : TEXCOORD1;
            };

            struct pixel_t
            {
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
                float4 vertex : SV_POSITION;
                fixed4 faceColor : COLOR;
                fixed4 outlineColor : COLOR1;
                float4 texcoord0 : TEXCOORD0; // Texture UV, Mask UV
                half4 param : TEXCOORD1; // Scale(x), BiasIn(y), BiasOut(z), Bias(w)
                half4 mask : TEXCOORD2; // Position in clip space(xy), Softness(zw)
            };


            pixel_t VertShader(vertex_t input)
            {
                pixel_t output;

                UNITY_INITIALIZE_OUTPUT(pixel_t, output);
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

                float bold = step(input.texcoord1.y, 0);

                float4 vert = input.vertex;
                vert.x += _VertexOffsetX;
                vert.y += _VertexOffsetY;
                float4 vPosition = UnityObjectToClipPos(vert);

                float2 pixelSize = vPosition.w;
                pixelSize /= float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));

                float scale = rsqrt(dot(pixelSize, pixelSize));
                scale *= abs(input.texcoord1.y) * _GradientScale * (_Sharpness + 1);
                if (UNITY_MATRIX_P[3][3] == 0) scale = lerp(abs(scale) * (1 - _PerspectiveFilter), scale, abs(dot(UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert)))));

                // 投影偏移
                vert.x += _UnderlayOffsetX * scale;
                vert.y += _UnderlayOffsetY * scale;
                vPosition = UnityObjectToClipPos(vert);

                float weight = lerp(_WeightNormal, _WeightBold, bold) / 4.0;
                weight = weight * _ScaleRatioA * 0.5;

                float bias = (0.5 - weight) * scale - 0.5;
                float outline = _UnderlayWidth * _ScaleRatioA * 0.5 * scale;

                float opacity = input.color.a;

                fixed4 faceColor = fixed4(input.color.rgb, opacity) * _FaceColor;
                faceColor.rgb *= faceColor.a;

                fixed4 outlineColor = _OutlineColor;
                outlineColor.a *= opacity;
                outlineColor.rgb *= outlineColor.a;
                outlineColor = lerp(faceColor, outlineColor, sqrt(min(1.0, (outline * 2))));

                // Generate UV for the Masking Texture
                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (vert.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);

                // Populate structure for pixel shader
                output.vertex = vPosition;
                output.faceColor = faceColor;
                output.outlineColor = outlineColor;
                output.texcoord0 = float4(input.texcoord0.x, input.texcoord0.y, maskUV.x, maskUV.y);
                output.param = half4(scale, bias - outline, bias + outline, bias);
                output.mask = half4(vert.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_MaskSoftnessX, _MaskSoftnessY) + pixelSize.xy));

                return output;
            }


            // PIXEL SHADER
            fixed4 PixShader(pixel_t input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);

                half d = tex2D(_MainTex, input.texcoord0.xy).a * input.param.x;
                half4 c = saturate(d - input.param.y) * _UnderlayColor;

                // Alternative implementation to UnityGet2DClipping with support for softness.
                #if UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(input.mask.xy)) * input.mask.zw);
                c *= m.x * m.y;
                #endif

                #if UNITY_UI_ALPHACLIP
                clip(c.a - 0.001);
                #endif

                return c;
            }
            ENDCG
        }


        Pass
        {
            Tags
            {
                "LightMode" = "UniversalForwardOnly"
            }
            
            CGPROGRAM
            #pragma vertex VertShader
            #pragma fragment PixShader

            #pragma multi_compile __ UNITY_UI_CLIP_RECT
            #pragma multi_compile __ UNITY_UI_ALPHACLIP
            #pragma shader_feature _ _OUTLINEON_ON

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            // UI Editable properties
            uniform sampler2D _FaceTex; // Alpha : Signed Distance
            uniform float _FaceUVSpeedX;
            uniform float _FaceUVSpeedY;
            uniform fixed4 _FaceColor; // RGBA : Color + Opacity

            uniform sampler2D _OutlineTex; // RGBA : Color + Opacity
            uniform float _OutlineUVSpeedX;
            uniform float _OutlineUVSpeedY;
            uniform fixed4 _OutlineColor; // RGBA : Color + Opacity
            uniform float _OutlineWidth; // v[ 0, 1]

            uniform float _Bevel; // v[ 0, 1]
            uniform float _BevelOffset; // v[-1, 1]
            uniform float _BevelWidth; // v[-1, 1]
            uniform float _BevelClamp; // v[ 0, 1]
            uniform float _BevelRoundness; // v[ 0, 1]

            uniform sampler2D _BumpMap; // Normal map
            uniform float _BumpOutline; // v[ 0, 1]
            uniform float _BumpFace; // v[ 0, 1]

            uniform samplerCUBE _Cube; // Cube / sphere map
            uniform fixed4 _ReflectFaceColor; // RGB intensity
            uniform fixed4 _ReflectOutlineColor;
            //uniform float        _EnvTiltX;                    // v[-1, 1]
            //uniform float        _EnvTiltY;                    // v[-1, 1]
            uniform float3 _EnvMatrixRotation;
            uniform float4x4 _EnvMatrix;

            uniform fixed4 _SpecularColor; // RGB intensity
            uniform float _LightAngle; // v[ 0,Tau]
            uniform float _SpecularPower; // v[ 0, 1]
            uniform float _Reflectivity; // v[ 5, 15]
            uniform float _Diffuse; // v[ 0, 1]
            uniform float _Ambient; // v[ 0, 1]

            uniform fixed4 _UnderlayColor; // RGBA : Color + Opacity
            uniform float _UnderlayOffsetX; // v[-1, 1]
            uniform float _UnderlayOffsetY; // v[-1, 1]

            uniform fixed4 _GlowColor; // RGBA : Color + Intesity
            uniform float _GlowOffset; // v[-1, 1]
            uniform float _GlowOuter; // v[ 0, 1]
            uniform float _GlowInner; // v[ 0, 1]
            uniform float _GlowPower; // v[ 1, 1/(1+4*4)]

            // API Editable properties
            uniform float _ShaderFlags;
            uniform float _WeightNormal;
            uniform float _WeightBold;

            uniform float _ScaleRatioA;
            uniform float _ScaleRatioB;
            uniform float _ScaleRatioC;

            uniform float _VertexOffsetX;
            uniform float _VertexOffsetY;

            //uniform float        _UseClipRect;
            uniform float _MaskID;
            uniform sampler2D _MaskTex;
            uniform float4 _MaskCoord;
            uniform float4 _ClipRect; // bottom left(x,y) : top right(z,w)
            //uniform float        _MaskWipeControl;
            //uniform float        _MaskEdgeSoftness;
            //uniform fixed4        _MaskEdgeColor;
            //uniform bool        _MaskInverse;

            uniform float _MaskSoftnessX;
            uniform float _MaskSoftnessY;

            // Font Atlas properties
            uniform sampler2D _MainTex;
            uniform float _TextureWidth;
            uniform float _TextureHeight;
            uniform float _GradientScale;
            uniform float _ScaleX;
            uniform float _ScaleY;
            uniform float _PerspectiveFilter;
            uniform float _Sharpness;


            struct vertex_t
            {
                UNITY_VERTEX_INPUT_INSTANCE_ID
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                fixed4 color : COLOR;
                float2 texcoord0 : TEXCOORD0;
                float2 texcoord1 : TEXCOORD1;
            };

            struct pixel_t
            {
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
                float4 vertex : SV_POSITION;
                fixed4 faceColor : COLOR;
                fixed4 outlineColor : COLOR1;
                float4 texcoord0 : TEXCOORD0; // Texture UV, Mask UV
                half4 param : TEXCOORD1; // Scale(x), BiasIn(y), BiasOut(z), Bias(w)
                half4 mask : TEXCOORD2; // Position in clip space(xy), Softness(zw)

                half4 color : TEXCOORD3;
            };


            pixel_t VertShader(vertex_t input)
            {
                pixel_t output;

                UNITY_INITIALIZE_OUTPUT(pixel_t, output);
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

                float bold = step(input.texcoord1.y, 0);

                float4 vert = input.vertex;
                vert.x += _VertexOffsetX;
                vert.y += _VertexOffsetY;
                float4 vPosition = UnityObjectToClipPos(vert);

                float2 pixelSize = vPosition.w;
                pixelSize /= float2(_ScaleX, _ScaleY) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));

                float scale = rsqrt(dot(pixelSize, pixelSize));
                scale *= abs(input.texcoord1.y) * _GradientScale * (_Sharpness + 1);
                if (UNITY_MATRIX_P[3][3] == 0) scale = lerp(abs(scale) * (1 - _PerspectiveFilter), scale, abs(dot(UnityObjectToWorldNormal(input.normal.xyz), normalize(WorldSpaceViewDir(vert)))));

                float weight = lerp(_WeightNormal, _WeightBold, bold) / 4.0;
                weight = weight * _ScaleRatioA * 0.5;

                float bias = (0.5 - weight) * scale - 0.5;
                float outline = _OutlineWidth * _ScaleRatioA * 0.5 * scale;

                float opacity = input.color.a;

                fixed4 faceColor = fixed4(input.color.rgb, opacity) * _FaceColor;
                faceColor.rgb *= faceColor.a;

                fixed4 outlineColor = _OutlineColor;
                outlineColor.a *= opacity;
                outlineColor.rgb *= outlineColor.a;
                outlineColor = lerp(faceColor, outlineColor, sqrt(min(1.0, (outline * 2))));

                // Generate UV for the Masking Texture
                float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
                float2 maskUV = (vert.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);

                // Populate structure for pixel shader
                output.vertex = vPosition;
                output.faceColor = faceColor;
                output.outlineColor = outlineColor;
                output.texcoord0 = float4(input.texcoord0.x, input.texcoord0.y, maskUV.x, maskUV.y);
                output.param = half4(scale, bias - outline, bias + outline, bias);
                output.mask = half4(vert.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_MaskSoftnessX, _MaskSoftnessY) + pixelSize.xy));

                output.color = input.color;
                return output;
            }


            half4 Bold(half4 oldBold, half4 param, half4 outlineColor, float2 uv, float2 offset)
            {
                half d1 = tex2D(_MainTex, uv + offset).a * param.x;
                //half mask1 = saturate(d1 - param.w);
                half4 c1 = outlineColor * saturate(d1 - param.w);
                return max(c1, oldBold);
            }

            // PIXEL SHADER
            fixed4 PixShader(pixel_t input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);

                half d = tex2D(_MainTex, input.texcoord0.xy).a * input.param.x;
                half mask = saturate(d - input.param.w);
                half4 c = input.faceColor * saturate(d - input.param.w);

                #if _OUTLINEON_ON
                half4 bold = 0;
                float offset = 0.002 * _OutlineWidth;
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(offset, offset));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(offset, -offset));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(-offset, offset));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(-offset, -offset));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(offset, 0));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(-offset, 0));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(0, offset));
                bold = Bold(bold, input.param, input.outlineColor, input.texcoord0, float2(0, -offset));
                c = lerp(bold, c, mask);
                #endif

                // 描边
                // half4 c = lerp(input.outlineColor, input.faceColor, saturate(d - input.param.w));
                // c *= saturate(d - input.param.y);

                // Alternative implementation to UnityGet2DClipping with support for softness.
                #if UNITY_UI_CLIP_RECT
                half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(input.mask.xy)) * input.mask.zw);
                c *= m.x * m.y;
                #endif

                #if UNITY_UI_ALPHACLIP
                clip(c.a - 0.001);
                #endif

                return c;
            }
            ENDCG
        }
    }

    //CustomEditor "TMPro.EditorUtilities.TMP_SDFShaderGUI"
    //CustomEditor "LWGUI.LWGUI"

}
View Code

 

#ifndef CUSTOM_WEATHER_INCLUDED
#define CUSTOM_WEATHER_INCLUDED

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"

// snow
uniform float _GlobalRoughnessOffset;
uniform float _SnowWeight;
uniform half4 _SnowColor;

uniform TEXTURE2D(_SnowMaskMap);
SAMPLER(sampler_SnowMaskMap);

// rain
uniform half4 _PuddleColor;
uniform float _PuddleWeight;
uniform float _RippleSpeed;
uniform float _RippleNormalStrength;

uniform TEXTURE2D(_RippleMaskMap);
SAMPLER(sampler_RippleMaskMap);

// water flow
uniform TEXTURE2D(_WaterFlowMap);
SAMPLER(sampler_WaterFlowMap);

float CalcSnowMask(float3 positionWS, float3 NModel, out float3 snowNormalTS, out float snowAO)
{
    // snow
    half NoUP = dot(NModel, float3(0,1,0));
    half snowMask = saturate(NoUP + 0.2) * _SnowWeight;
                
    //
    half4 snowMaskMap = SAMPLE_TEXTURE2D(_SnowMaskMap, sampler_SnowMaskMap, positionWS.xz * 0.02);
                
    // normal
    float2 snowNormalXY = snowMaskMap.rg * 2 - 1;
    snowNormalXY *= 0.2;
    float snowNormalZ = sqrt(1 - dot(snowNormalXY, snowNormalXY));
    snowNormalTS = normalize(float3(snowNormalXY, snowNormalZ));
                
    // ao
    snowAO = snowMaskMap.b;
                
    return snowMask;
}

void BlendSnow(inout SurfaceData surfaceData, float3 positionWS, float3 NModel)
{
    float3 snowNormalTS;
    float snowAO;
    half snowMask = CalcSnowMask(positionWS, NModel, snowNormalTS, snowAO);
    
    surfaceData.albedo = lerp(surfaceData.albedo, _SnowColor.rgb, snowMask);
    surfaceData.metallic = lerp(surfaceData.metallic, 0, snowMask);
    surfaceData.smoothness = lerp(surfaceData.smoothness, 0, snowMask);
    surfaceData.occlusion = lerp(surfaceData.occlusion, snowAO, snowMask);
    surfaceData.normalTS = lerp(surfaceData.normalTS, snowNormalTS, snowMask);
}

// rain
float3 CalcRippleNormal(float3 positionWS, float offset, out float rippleMask)
{
    half4 rippleMaskMap = SAMPLE_TEXTURE2D(_RippleMaskMap, sampler_RippleMaskMap, positionWS.xz * 0.08 + offset.xx);
    rippleMask = rippleMaskMap.r * saturate(1 - abs(rippleMaskMap.r + frac(_Time.y * _RippleSpeed + offset) - 1) * 10);
    
    float2 rippleNormalXY = rippleMaskMap.gb * 2 - 1;
    float rippleNormalZ = sqrt(1 - dot(rippleNormalXY, rippleNormalXY));
    float3 rippleNormal = normalize(float3(rippleNormalXY * _RippleNormalStrength, rippleNormalZ));
    return rippleNormal;
}

void BlendRainPubbleNormal(float finalPuddleWeight, float3 positionWS, inout float3 normalTS)
{
    // ripple 1
    float rippleMask1;
    float3 rippleNormal1 = CalcRippleNormal(positionWS, 0, rippleMask1);
    normalTS = lerp(normalTS, rippleNormal1, rippleMask1 * finalPuddleWeight);

    // ripple 2
    float rippleMask2;
    float3 rippleNormal2 = CalcRippleNormal(positionWS, 0.5, rippleMask2);
    normalTS = lerp(normalTS, rippleNormal2, rippleMask2 * finalPuddleWeight);
}

void BlendRainPupple(float puddleWeight, float3 positionWS, inout half3 albedo, inout float3 normalTS, inout float roughness)
{
    // pubble
    float finalPuddleWeight = _PuddleWeight * puddleWeight;
    albedo = lerp(albedo, _PuddleColor.rgb, saturate(finalPuddleWeight + _PuddleColor.a - 1));
    roughness = lerp(roughness, 0, finalPuddleWeight);
    normalTS = lerp(normalTS, float3(0, 0, 1), finalPuddleWeight);

    BlendRainPubbleNormal(finalPuddleWeight, positionWS, normalTS);
}

// water flow
void WaterFlow(float2 uv, float3 NModel, inout float3 normalTS, inout float smoothness)
{
    float2 uv_Rain = uv * 2;
    float4 wetMap = SAMPLE_TEXTURE2D(_WaterFlowMap, sampler_WaterFlowMap, uv_Rain);
    float3 tangentWetNormal = normalize(float3(wetMap.zw * 2 - 1, 1));
    
    uv_Rain.y += _Time.x * _RippleSpeed;
    float4 rainMaskMap = SAMPLE_TEXTURE2D(_WaterFlowMap, sampler_WaterFlowMap, uv_Rain);
    float rainMask = saturate((wetMap.r - pow(rainMaskMap.g, 8)) * 5);
    
    half NoUP = dot(NModel, float3(0,1,0));
    rainMask *= saturate(1 - NoUP);
    
    normalTS = lerp(normalTS, tangentWetNormal, rainMask);
    smoothness = lerp(smoothness, 1, rainMask);
}


#endif
View Code

 

posted @ 2023-04-18 17:04  太乙_真人  阅读(365)  评论(0)    收藏  举报