This commit is contained in:
JA
2026-06-27 03:37:32 +08:00
parent 3059e71422
commit 7969e2e35d
368 changed files with 20297 additions and 58206 deletions

View File

@@ -0,0 +1,148 @@
Shader "IndianOcean/SpriteEchoOutline"
{
// 回声描边 Shader —— 配合 EchoSystem 使用
// 渲染精灵的"外描边",颜色默认白色(可自定义),由全局回声参数控制显隐。
// 渲染队列在黑暗遮罩Transparent+100之上Transparent+200
// 所以即使在黑暗中(黑暗遮罩把场景乘成纯黑),描边依然可见。
//
// 工作原理:
// - 顶点着色器:以精灵中心为基准向外扩展顶点,为外描边腾出空间
// - 片元着色器8 方向膨胀采样精灵 alpha邻居有 alpha 但中心没有 → 描边像素
// - 回声控制:精灵世界坐标距 _EchoCenter 小于 _EchoRadius 才显示描边
Properties
{
_MainTex ("Sprite Texture", 2D) = "white" {}
_OutlineColor ("描边颜色(乘以全局回声颜色,默认白)", Color) = (1,1,1,1)
_OutlineWidth ("描边宽度(像素/纹素)", Range(0, 8)) = 2.0
}
SubShader
{
Tags
{
"RenderType" = "Transparent"
"Queue" = "Transparent+200"
"RenderPipeline" = "UniversalPipeline"
}
// 普通半透明叠加(在黑暗遮罩之后渲染,所以不被黑暗乘掉)
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off
Pass
{
Name "EchoOutline"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#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;
float2 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
CBUFFER_START(UnityPerMaterial)
float4 _OutlineColor;
float _OutlineWidth;
float4 _MainTex_ST;
CBUFFER_END
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_TexelSize;
// 全局回声参数(由 EchoSystem 通过 Shader.SetGlobalX 设置,不是材质属性)
float4 _EchoCenter; // xy = 回声中心世界坐标 XZ
float _EchoRadius; // 当前波纹前沿半径
float _EchoWidth; // 波纹前沿柔和宽度
float _EchoOutlineIntensity; // 整体描边强度(维持=1, 消散=1→0, 关闭=0
float4 _EchoOutlineColor; // 全局描边颜色(默认白色)
// 8 方向采样偏移(对角线用 0.7071 保持等距)
static const float2 _Offsets[8] = {
float2( 1.0, 0.0), float2(-1.0, 0.0), float2( 0.0, 1.0), float2( 0.0, -1.0),
float2( 0.7071, 0.7071), float2(-0.7071, 0.7071),
float2( 0.7071, -0.7071), float2(-0.7071, -0.7071)
};
// 带边界检查的 alpha 采样UV 超出 [0,1] 视为空0避免边缘错误填充
float sampleAlphaBounded(float2 uv)
{
float a = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv).a;
float inBounds = step(0.0, uv.x) * step(uv.x, 1.0)
* step(0.0, uv.y) * step(uv.y, 1.0);
return a * inBounds;
}
Varyings vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
float3 posOS = input.positionOS.xyz;
output.positionCS = TransformObjectToHClip(posOS);
output.uv = TRANSFORM_TEX(input.uv, _MainTex);
output.worldPos = TransformObjectToWorld(posOS);
// 以精灵中心为基准向外扩展顶点,为外描边腾出屏幕空间
float4 centerCS = TransformObjectToHClip(float3(0,0,0));
float2 csDir = output.positionCS.xy - centerCS.xy;
float len = length(csDir);
csDir = (len > 0.0001) ? csDir / len : float2(1.0, 0.0);
float2 ndcPerPixel = 2.0 / _ScreenParams.xy;
output.positionCS.xy += csDir * ndcPerPixel * _OutlineWidth;
return output;
}
half4 frag(Varyings input) : SV_Target
{
// ===== 回声距离检查 =====
// 波纹前沿在 _EchoRadius精灵距中心小于半径 → 已被扫描 → 显示描边
float2 wp = input.worldPos.xz;
float ed = distance(wp, _EchoCenter.xy);
// smoothstep: 距离从 (radius-width) 到 radius 时从1降到0取反 = 半径内为1
float reached = 1.0 - smoothstep(_EchoRadius - _EchoWidth, _EchoRadius, ed);
float intensity = reached * _EchoOutlineIntensity;
// 回声未到达或已关闭 → 直接丢弃,零开销
if (intensity < 0.001) discard;
// ===== 膨胀采样得到描边 =====
float2 uv = input.uv;
float origAlpha = sampleAlphaBounded(uv);
float2 texel = _MainTex_TexelSize.xy;
float w = max(1.0, _OutlineWidth);
float dilatedAlpha = 0.0;
[unroll]
for (int i = 0; i < 8; i++)
{
float2 ouv = uv + _Offsets[i] * texel * w;
dilatedAlpha = max(dilatedAlpha, sampleAlphaBounded(ouv));
}
// 描边 = 邻居有 alpha 但中心没有(外描边)
float outline = step(0.5, dilatedAlpha) * (1.0 - step(0.5, origAlpha));
// ===== 输出 =====
float3 col = _EchoOutlineColor.rgb * _OutlineColor.rgb;
float alpha = outline * intensity * _EchoOutlineColor.a * _OutlineColor.a;
return half4(col, alpha);
}
ENDHLSL
}
}
FallBack Off
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: Dn9OtiKqB35oskIeVe74RmLVIVNUFiTsesLMxl9tEuOicYXOA+RAQzY=
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant: