Shader "Soullies/DTM_RandomGridTube" { Properties { [HDR]_Color0("Color0", Color) = (1, 1, 1, 0) [Header(Pattern Settings)] _PatternSize("Pattern Size (X, Y)", Vector) = (2.0, 2.0, 0, 0) _GridDensity("Grid Density (Quantity Multiplier)", Float) = 1.0 _BaseSpeed("Base Speed (Static)", Float) = 1.0 _TimeAngle("Time Angle / Offset (Dynamic)", Float) = 0.0 [Header(Edge Settings)] _StepA("Step A", Range(0, 1)) = 0.293 _StepB("Step B", Range(0, 1)) = 0.345 [Header(Seam Hiding)] _SeamRotation("Seam Angle Offset", Range(-180, 180)) = -90.0 _SeamFadeWidth("Seam Cut Width", Range(0.0, 1.0)) = 0.2 _SeamFadeSmoothness("Seam Softness", Range(0.0, 1.0)) = 1.0 [Header(Tube Specific Settings)] _FadeFar("Fade Far (Fully Transparent)", Float) = 100.0 _FadeNear("Fade Near (Fully Opaque)", Float) = 20.0 _TubeRadius("Virtual Tube Radius", Float) = 10.0 [Header(Render State)] [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend", Float) = 5 // SrcAlpha [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend", Float) = 10 // OneMinusSrcAlpha [Enum(Off, 0, On, 1)] _ZWrite("Z Write", Float) = 0 [Enum(Front, 0, Back, 1, Off, 2)] _CullMode("Cull Mode", Float) = 1 // Front (Inside) } SubShader { Tags { "RenderPipeline" = "UniversalPipeline" "RenderType" = "Transparent" "Queue" = "Transparent-300" "UniversalMaterialType" = "Unlit" "IgnoreProjector" = "True" } Blend [_SrcBlend] [_DstBlend] ZWrite [_ZWrite] Cull [_CullMode] // Default Cull Front to see inside the tube Pass { Name "ForwardOnly" Tags { "LightMode" = "UniversalForwardOnly" } HLSLPROGRAM #pragma target 4.5 #pragma prefer_hlslcc gles #pragma multi_compile_instancing #pragma multi_compile_fog #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float3 positionWS : TEXCOORD0; float3 positionOS : TEXCOORD1; half fogFactor : TEXCOORD3; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; CBUFFER_START(UnityPerMaterial) half4 _Color0; float4 _PatternSize; float _GridDensity; float _BaseSpeed; float _TimeAngle; float _StepA; float _StepB; float _SeamRotation; float _SeamFadeWidth; float _SeamFadeSmoothness; float _FadeFar; float _FadeNear; float _TubeRadius; CBUFFER_END // ------------------------------------- // 极限优化工具库组 (无三角函数,全MAD指令) // Fast 2D Hash (纯乘加与小数截断,干掉 sin) float2 FastHash22(float2 p) { float3 p3 = frac(float3(p.xyx) * float3(0.1031, 0.1030, 0.0973)); p3 += dot(p3, p3.yzx + 33.33); return frac((p3.xx + p3.yz) * p3.zy); } // Extreme Optimized 4-Tap Voronoi for Mobile (从9次循环砍至4次) float VoronoiDistanceFast(float2 v, float t) { float2 n = floor(v); float2 f = frac(v); // 象限锚定:算出像素所处方格的偏向,完美剔除背面5个不可能相邻的远格 float2 mg = step(0.5, f); float minDist = 8.0; UNITY_UNROLL for (int j = 0; j <= 1; j++) { UNITY_UNROLL for (int i = 0; i <= 1; i++) { // 检索偏向象限的核心 4 个格子 float2 g = mg + float2(i - 1.0, j - 1.0); float2 hash = FastHash22(n + g); // 剔除昂贵的 sin 并换用平滑三角波: // t * 0.1591549 即相当于 t / (2*PI) 把时间归一化到周期 float2 phase = frac(t * 0.1591549 + hash); float2 tri = abs(phase * 2.0 - 1.0); // 线性三角波 1 -> 0 -> 1 float2 o = tri * tri * (3.0 - 2.0 * tri); // 光滑三次曲线,模拟 sin 的柔顺运动 float2 r = f - g - o; // Manhattan 曼哈顿距离 float d = 0.5 * (abs(r.x) + abs(r.y)); minDist = min(minDist, d); } } return minDist; } // ------------------------------------- // Vertex Shader Varyings vert(Attributes input) { Varyings output = (Varyings)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); output.positionCS = vertexInput.positionCS; output.positionWS = vertexInput.positionWS; output.positionOS = input.positionOS.xyz; output.fogFactor = ComputeFogFactor(vertexInput.positionCS.z); return output; } // ------------------------------------- // Fragment Shader half4 frag(Varyings input) : SV_Target { UNITY_SETUP_INSTANCE_ID(input); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); // ========================================== // 1. Cylindrical Mapping & Seam Control // ========================================== // Calculate angle around the Z-axis in object space. atan2 returns [-PI, PI]. float rawAngle = atan2(input.positionOS.y, input.positionOS.x); // Rotate the seam mechanically float angleOffset = _SeamRotation * (3.14159265 / 180.0); float angle = rawAngle + angleOffset; // Wrap angle to [-PI, PI] to keep math bounded if(angle > 3.14159265) angle -= 6.2831853; if(angle < -3.14159265) angle += 6.2831853; // Derive distance to the seam (seam is at absolute PI or -PI) float distToSeam = 3.14159265 - abs(angle); // Seam alpha fading calculation float endFade = _SeamFadeWidth * 3.14159265; float startFade = endFade * (1.0 - _SeamFadeSmoothness); float seamFadeMask = smoothstep(startFade, endFade + 0.0001, distToSeam); // Convert adjusted angle to U coordinate float u = angle * _TubeRadius; // V is driven by Object Z scaled by World Scale to maintain seamless tiling and resist rotation stretching float scaleZ = length(float3(unity_ObjectToWorld[0].z, unity_ObjectToWorld[1].z, unity_ObjectToWorld[2].z)); float v = input.positionOS.z * scaleZ; float2 cylindricalUV = float2(u, v); // Density Multiplier float density = max(_GridDensity, 0.0001); float2 sizeDivisor = max(_PatternSize.xy, float2(0.0001, 0.0001)) / density; float2 scaledUV = cylindricalUV / sizeDivisor; // Rotate 45 degrees float c = 0.707106; float s = 0.707106; float2 rotatedUV = mul(scaledUV, float2x2(c, -s, s, c)); // Time driven animation (Base Time + Phase Offset) float t = _TimeParameters.x * _BaseSpeed + _TimeAngle; // [TA 极限计算压缩] 使用 4-Tap、零三角函数的极简数学方法,保持无限分辨率。 float voronoiV = VoronoiDistanceFast(rotatedUV, t); // Anti-aliased border mask computation float fw = fwidth(voronoiV); float edge1 = smoothstep(_StepA - fw, _StepA + fw, voronoiV); float edge2 = smoothstep(_StepB - fw, _StepB + fw, voronoiV); float gridAlphaMask = edge2 - edge1; half3 gridColor = _Color0.rgb; half gridAlpha = gridAlphaMask * _Color0.a; // ========================================== // 2. Distance Fade (Far = Transparent, Near = Opaque) // ========================================== float distToCam = distance(GetCameraPositionWS(), input.positionWS); // If distToCam is between _FadeFar and _FadeNear, smoothly transition // When dist = _FadeFar, fadeMask = 0 (Transparent) // When dist = _FadeNear, fadeMask = 1 (Opaque) float rawFade = (distToCam - _FadeFar) / (_FadeNear - _FadeFar + 0.0001); float fadeMask = saturate(rawFade); // Multiply the alpha by our camera distance fade AND seam smooth fade gridAlpha *= fadeMask * seamFadeMask; // Apply URP Fog gridColor = MixFog(gridColor, input.fogFactor); return half4(gridColor, gridAlpha); } ENDHLSL } } FallBack "Hidden/Universal Render Pipeline/FallbackError" }