Files
Cielonos/Assets/Shaders/MeshShader/Outline.shader
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

164 lines
6.5 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
}