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 }
毛皮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 }
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 }
效果:

转载请注明出处: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 } }
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" }
#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

浙公网安备 33010602011771号