2026-03-21 12:12:12 -04:00
|
|
|
|
Shader "Soullies/DTM_RandomGridTube"
|
2026-03-18 13:42:23 -04:00
|
|
|
|
{
|
|
|
|
|
|
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
|
2026-04-06 09:32:56 -04:00
|
|
|
|
_BaseSpeed("Base Speed (Static)", Float) = 1.0
|
|
|
|
|
|
_TimeAngle("Time Angle / Offset (Dynamic)", Float) = 0.0
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
[Header(Edge Settings)]
|
|
|
|
|
|
_StepA("Step A", Range(0, 1)) = 0.293
|
|
|
|
|
|
_StepB("Step B", Range(0, 1)) = 0.345
|
|
|
|
|
|
|
2026-03-21 12:12:12 -04:00
|
|
|
|
[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
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
[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
|
2026-04-06 09:32:56 -04:00
|
|
|
|
[Enum(Front, 0, Back, 1, Off, 2)] _CullMode("Cull Mode", Float) = 1 // Front (Inside)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SubShader
|
|
|
|
|
|
{
|
|
|
|
|
|
Tags
|
|
|
|
|
|
{
|
|
|
|
|
|
"RenderPipeline" = "UniversalPipeline"
|
|
|
|
|
|
"RenderType" = "Transparent"
|
|
|
|
|
|
"Queue" = "Transparent-300"
|
|
|
|
|
|
"UniversalMaterialType" = "Unlit"
|
|
|
|
|
|
"IgnoreProjector" = "True"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Blend [_SrcBlend] [_DstBlend]
|
|
|
|
|
|
ZWrite [_ZWrite]
|
2026-03-21 12:12:12 -04:00
|
|
|
|
Cull [_CullMode] // Default Cull Front to see inside the tube
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
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;
|
2026-03-21 12:12:12 -04:00
|
|
|
|
float3 positionOS : TEXCOORD1;
|
|
|
|
|
|
half fogFactor : TEXCOORD3;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
|
|
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
CBUFFER_START(UnityPerMaterial)
|
|
|
|
|
|
half4 _Color0;
|
|
|
|
|
|
float4 _PatternSize;
|
|
|
|
|
|
float _GridDensity;
|
2026-04-06 09:32:56 -04:00
|
|
|
|
float _BaseSpeed;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
float _TimeAngle;
|
|
|
|
|
|
float _StepA;
|
|
|
|
|
|
float _StepB;
|
2026-03-21 12:12:12 -04:00
|
|
|
|
float _SeamRotation;
|
|
|
|
|
|
float _SeamFadeWidth;
|
|
|
|
|
|
float _SeamFadeSmoothness;
|
|
|
|
|
|
float _FadeFar;
|
|
|
|
|
|
float _FadeNear;
|
|
|
|
|
|
float _TubeRadius;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
CBUFFER_END
|
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// 极限优化工具库组 (无三角函数,全MAD指令)
|
|
|
|
|
|
|
|
|
|
|
|
// Fast 2D Hash (纯乘加与小数截断,干掉 sin)
|
|
|
|
|
|
float2 FastHash22(float2 p)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
{
|
2026-04-06 09:32:56 -04:00
|
|
|
|
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);
|
2026-03-18 13:42:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// Extreme Optimized 4-Tap Voronoi for Mobile (从9次循环砍至4次)
|
|
|
|
|
|
float VoronoiDistanceFast(float2 v, float t)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
{
|
|
|
|
|
|
float2 n = floor(v);
|
|
|
|
|
|
float2 f = frac(v);
|
2026-04-06 09:32:56 -04:00
|
|
|
|
|
|
|
|
|
|
// 象限锚定:算出像素所处方格的偏向,完美剔除背面5个不可能相邻的远格
|
|
|
|
|
|
float2 mg = step(0.5, f);
|
|
|
|
|
|
|
2026-03-18 13:42:23 -04:00
|
|
|
|
float minDist = 8.0;
|
|
|
|
|
|
|
|
|
|
|
|
UNITY_UNROLL
|
2026-04-06 09:32:56 -04:00
|
|
|
|
for (int j = 0; j <= 1; j++)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
{
|
|
|
|
|
|
UNITY_UNROLL
|
2026-04-06 09:32:56 -04:00
|
|
|
|
for (int i = 0; i <= 1; i++)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
{
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// 检索偏向象限的核心 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 的柔顺运动
|
|
|
|
|
|
|
2026-03-18 13:42:23 -04:00
|
|
|
|
float2 r = f - g - o;
|
2026-04-06 09:32:56 -04:00
|
|
|
|
|
|
|
|
|
|
// Manhattan 曼哈顿距离
|
2026-03-18 13:42:23 -04:00
|
|
|
|
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;
|
2026-03-21 12:12:12 -04:00
|
|
|
|
output.positionOS = input.positionOS.xyz;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
// ==========================================
|
2026-03-21 12:12:12 -04:00
|
|
|
|
// 1. Cylindrical Mapping & Seam Control
|
2026-03-18 13:42:23 -04:00
|
|
|
|
// ==========================================
|
2026-03-21 12:12:12 -04:00
|
|
|
|
// 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;
|
|
|
|
|
|
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// 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;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
2026-03-21 12:12:12 -04:00
|
|
|
|
float2 cylindricalUV = float2(u, v);
|
|
|
|
|
|
|
|
|
|
|
|
// Density Multiplier
|
2026-03-18 13:42:23 -04:00
|
|
|
|
float density = max(_GridDensity, 0.0001);
|
|
|
|
|
|
float2 sizeDivisor = max(_PatternSize.xy, float2(0.0001, 0.0001)) / density;
|
|
|
|
|
|
|
2026-03-21 12:12:12 -04:00
|
|
|
|
float2 scaledUV = cylindricalUV / sizeDivisor;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
// Rotate 45 degrees
|
|
|
|
|
|
float c = 0.707106;
|
|
|
|
|
|
float s = 0.707106;
|
|
|
|
|
|
float2 rotatedUV = mul(scaledUV, float2x2(c, -s, s, c));
|
|
|
|
|
|
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// Time driven animation (Base Time + Phase Offset)
|
|
|
|
|
|
float t = _TimeParameters.x * _BaseSpeed + _TimeAngle;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
2026-04-06 09:32:56 -04:00
|
|
|
|
// [TA 极限计算压缩] 使用 4-Tap、零三角函数的极简数学方法,保持无限分辨率。
|
|
|
|
|
|
float voronoiV = VoronoiDistanceFast(rotatedUV, t);
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
// Anti-aliased border mask computation
|
2026-03-21 12:12:12 -04:00
|
|
|
|
float fw = fwidth(voronoiV);
|
|
|
|
|
|
float edge1 = smoothstep(_StepA - fw, _StepA + fw, voronoiV);
|
|
|
|
|
|
float edge2 = smoothstep(_StepB - fw, _StepB + fw, voronoiV);
|
2026-03-18 13:42:23 -04:00
|
|
|
|
float gridAlphaMask = edge2 - edge1;
|
|
|
|
|
|
|
|
|
|
|
|
half3 gridColor = _Color0.rgb;
|
|
|
|
|
|
half gridAlpha = gridAlphaMask * _Color0.a;
|
|
|
|
|
|
|
|
|
|
|
|
// ==========================================
|
2026-03-21 12:12:12 -04:00
|
|
|
|
// 2. Distance Fade (Far = Transparent, Near = Opaque)
|
2026-03-18 13:42:23 -04:00
|
|
|
|
// ==========================================
|
2026-03-21 12:12:12 -04:00
|
|
|
|
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;
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
|
|
|
|
|
// Apply URP Fog
|
2026-03-21 12:12:12 -04:00
|
|
|
|
gridColor = MixFog(gridColor, input.fogFactor);
|
2026-03-18 13:42:23 -04:00
|
|
|
|
|
2026-03-21 12:12:12 -04:00
|
|
|
|
return half4(gridColor, gridAlpha);
|
2026-03-18 13:42:23 -04:00
|
|
|
|
}
|
|
|
|
|
|
ENDHLSL
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
FallBack "Hidden/Universal Render Pipeline/FallbackError"
|
|
|
|
|
|
}
|