164 lines
6.5 KiB
GLSL
164 lines
6.5 KiB
GLSL
Shader "Cielonos/MeshEffects/Outline"
|
||
{
|
||
Properties
|
||
{
|
||
[Header(Outline Core Parameters)]
|
||
[HDR] _OutlineColor ("Outline Color (HDR)", Color) = (1, 0, 0, 1)
|
||
|
||
[Space(10)]
|
||
_OutlineWidth ("Base Outline Width", Range(0.0, 0.1)) = 0.01
|
||
|
||
_MinScreenThickness ("Lower Bound (Distance-Based Width)", Range(0.0, 10.0)) = 1.0
|
||
|
||
_OutlineScale ("Outline Transition Scale (Animation)", Range(0.0, 1.0)) = 1.0
|
||
|
||
[Toggle] _UseVertexColorMask ("Use Vertex Color Alpha as Mask", Float) = 0.0
|
||
|
||
[Header(Flow Texture)]
|
||
_OutlineTexture ("Flow Texture", 2D) = "white" {}
|
||
_FlowSpeedU ("Flow Speed U", Float) = 0.0
|
||
_FlowSpeedV ("Flow Speed V", Float) = 0.0
|
||
|
||
[Header(Render State)]
|
||
[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1 // One
|
||
[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0 // Zero
|
||
[Enum(UnityEngine.Rendering.CullMode)] _Cull ("Culling", Float) = 1 // Front
|
||
[Enum(Off,0,On,1)] _ZWrite ("Z Write", Float) = 1
|
||
[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("Z Test", Float) = 4 // LEqual
|
||
}
|
||
|
||
SubShader
|
||
{
|
||
Tags
|
||
{
|
||
// 如果作为基于屏幕后期组合之前的几何体Pass,可以选用更合适的 RenderType
|
||
// 此处设定为不透明,并且在常规几何体之后绘制
|
||
"RenderType"="Opaque"
|
||
"RenderPipeline"="UniversalPipeline"
|
||
"Queue"="AlphaTest+50"
|
||
}
|
||
|
||
Pass
|
||
{
|
||
Name "CharacterStateOutline"
|
||
Tags { "LightMode" = "SRPDefaultUnlit" }
|
||
|
||
Cull [_Cull]
|
||
ZWrite [_ZWrite]
|
||
ZTest [_ZTest]
|
||
Blend [_SrcBlend] [_DstBlend]
|
||
|
||
HLSLPROGRAM
|
||
// 因为明确是 PC 端,直接上 Target 4.5 获得更好的指令支持
|
||
#pragma target 4.5
|
||
|
||
#pragma vertex vert
|
||
#pragma fragment frag
|
||
|
||
// 暴露 keyword 给面板复选框
|
||
#pragma shader_feature_local _USEVERTEXCOLORMASK_ON
|
||
|
||
// 包含 URP 核心库
|
||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||
|
||
struct Attributes
|
||
{
|
||
float4 positionOS : POSITION;
|
||
float3 normalOS : NORMAL;
|
||
float2 uv : TEXCOORD0;
|
||
float4 color : COLOR;
|
||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||
};
|
||
|
||
struct Varyings
|
||
{
|
||
float4 positionCS : SV_POSITION;
|
||
float2 uv : TEXCOORD0;
|
||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||
UNITY_VERTEX_OUTPUT_STEREO
|
||
};
|
||
|
||
// Cbuffer 声明以支持 SRP Batcher 优化,这在 Render Graph 下极其重要
|
||
CBUFFER_START(UnityPerMaterial)
|
||
half4 _OutlineColor;
|
||
float _OutlineWidth;
|
||
float _MinScreenThickness;
|
||
float _OutlineScale;
|
||
float _FlowSpeedU;
|
||
float _FlowSpeedV;
|
||
float4 _OutlineTexture_ST;
|
||
CBUFFER_END
|
||
|
||
TEXTURE2D(_OutlineTexture);
|
||
SAMPLER(sampler_OutlineTexture);
|
||
|
||
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);
|
||
|
||
// --- 描边核心算法:距离感知的自适应法线外扩 ---
|
||
|
||
// 1. 获取世界空间位置与法线
|
||
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
|
||
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
|
||
|
||
// 2. 计算摄像机到顶点的真实距离
|
||
// 我们在最高质量要求下不使用带透视除法的 ClipSpace.w,而是精确判断到相机的绝对距离
|
||
float distToCam = distance(GetCameraPositionWS(), positionWS);
|
||
|
||
// 3. 动态控制描边宽度:基础宽度 vs 结合距离修正的最小宽度
|
||
// 解释:这实际上是通过构建一个根据距离放大的“屏占比安全下界”。
|
||
// _MinScreenThickness * 0.001 意味着参数面板上给个 1.0 时,能得到极好控制感
|
||
float minWidth = _MinScreenThickness * distToCam * 0.001;
|
||
float finalWidth = max(_OutlineWidth, minWidth);
|
||
|
||
// 应用全局缩放系数,用于实现淡出/消失的动画
|
||
finalWidth *= _OutlineScale;
|
||
|
||
// 4. 获取遮罩影响(如果启用了顶点颜色通道遮罩)
|
||
#ifdef _USEVERTEXCOLORMASK_ON
|
||
// 利用顶点色的 Alpha 通道进行描边权重遮罩(如脸部不想要描边,可刷为0)
|
||
finalWidth *= input.color.a;
|
||
#endif
|
||
|
||
// 5. 沿法线方向挤出顶点
|
||
positionWS += normalize(normalWS) * finalWidth;
|
||
|
||
// 6. 转换回裁剪空间
|
||
output.positionCS = TransformWorldToHClip(positionWS);
|
||
|
||
// 传递并处理流动 UV 的 Tiling 和 Offset
|
||
output.uv = TRANSFORM_TEX(input.uv, _OutlineTexture);
|
||
|
||
return output;
|
||
}
|
||
|
||
half4 frag(Varyings input) : SV_Target
|
||
{
|
||
UNITY_SETUP_INSTANCE_ID(input);
|
||
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
|
||
|
||
// UV 滚动逻辑
|
||
float2 flowOffset = float2(_FlowSpeedU, _FlowSpeedV) * _Time.y;
|
||
float2 finalUV = input.uv + flowOffset;
|
||
|
||
// 采样流动纹理,由于是作为 Mask 或者渐变,使用最高精度的采样器
|
||
half4 flowTexColor = SAMPLE_TEXTURE2D(_OutlineTexture, sampler_OutlineTexture, finalUV);
|
||
|
||
// 将流光纹理和高动态范围(HDR)的发光颜色完美结合
|
||
// 半精度 half4 已足够满足输出和 Bloom 后处理需求
|
||
half4 finalColor = _OutlineColor * flowTexColor;
|
||
|
||
return finalColor;
|
||
}
|
||
ENDHLSL
|
||
}
|
||
}
|
||
|
||
// Editor Fallback,发生编译错误时会高亮为品红
|
||
FallBack "Hidden/Universal Render Pipeline/FallbackError"
|
||
}
|