给我一个可以在unity中可以使用的高亮描边的shader,他可以接受透明度调整
时间: 2025-08-05 22:08:20 AIGC 浏览: 16
<think>我们被要求提供一个支持透明度调整的高亮描边Shader。根据用户需求,我们需要实现一个描边效果,并且可以调整透明度(可能是整个材质的透明度,也可能是描边部分的透明度)。同时,参考引用[1]中提到了描边宽度、颜色和强度的调整,我们也要支持这些参数。
常见的描边实现方法有两种:
1. 基于法线外扩的描边(在顶点着色器中沿法线方向扩张顶点)
2. 基于屏幕后处理的描边(使用边缘检测算法)
这里用户要求的是Shader,并且没有指定是后处理还是物体本身,通常对于单个物体的描边,我们使用法线外扩的方法。同时,为了支持透明度,我们需要在片元着色器中处理透明通道。
注意:透明度调整通常通过改变颜色的alpha值来实现。我们可能需要两个颜色属性:一个用于物体本身(包含透明度),一个用于描边(也包含透明度)。或者,我们可以将描边颜色和物体颜色分开控制,并分别提供透明度控制。
由于用户要求高亮描边,并且支持透明度调整,我们将设计一个支持以下属性的Shader:
- _MainTex: 主纹理
- _MainColor: 主颜色(包含透明度)
- _OutlineColor: 描边颜色(包含透明度)
- _OutlineWidth: 描边宽度
- 可能还需要一个参数来控制描边的强度(如引用[1]所述),但我们可以将其合并到_OutlineColor的alpha中,或者单独设置一个_OutlineIntensity。
但是,请注意,描边的外扩通常是在模型空间进行的,所以当模型缩放不一致时,可能会导致描边不均匀。我们可以使用一个统一的缩放因子来调整。
实现步骤:
1. 在顶点着色器中,我们复制两组顶点数据:一组用于渲染物体本身,一组用于渲染描边(将顶点沿法线方向外扩)。
2. 使用两个Pass:第一个Pass渲染描边(外扩的顶点),第二个Pass渲染物体本身。
3. 在描边Pass中,我们只输出描边颜色(包括透明度),在物体Pass中,我们输出物体本身的颜色(包括透明度)。
注意:由于描边Pass会先绘制,物体Pass后绘制,所以物体会覆盖在描边之上,从而形成描边效果。
但是,透明度混合时,我们需要考虑混合模式。如果物体本身是半透明的,那么描边也应该能够透过物体显示?通常描边是在物体边缘,所以即使物体半透明,描边也应该是不透明的?这取决于需求。我们可以提供混合选项。
不过,为了简单起见,我们让描边Pass使用深度测试(ZTest)设置为Always(这样描边总是被绘制,但可能会被其他物体遮挡)或者Less(这样描边在物体后面,但物体本身会覆盖描边的内部部分)。通常我们使用:
描边Pass:ZTest Always(或者Greater,这样描边只在物体后面绘制,但为了确保描边可见,通常使用Always)但是这样会绘制在场景所有物体之上,可能不是我们想要的。
更常见的做法是:
描边Pass:将深度测试设置为Less,并稍微将描边往后推一点(通过修改顶点在视图空间中的深度值)以避免深度冲突。但这样会增加复杂度。
另一种简单做法:描边Pass关闭深度写入(ZWrite Off),深度测试设置为LessEqual,然后正常绘制。这样描边只会在物体后面的部分绘制出来,但这样描边可能被其他物体遮挡。
考虑到用户要求的是高亮描边,通常希望描边是可见的,所以我们采用:
描边Pass:ZWrite Off, ZTest Always 这样描边总是绘制,并且不会写入深度,这样物体本身绘制时会覆盖掉描边重叠的部分(因为物体Pass会写入深度)。但是这样会导致描边可能穿过其他物体。
我们也可以使用两个Pass都写入深度,但描边Pass先绘制,然后物体Pass绘制时覆盖掉描边在物体表面的部分。这样描边在物体轮廓处显示,内部被物体覆盖。这是常用的方法。
具体实现:
描边Pass:
- 顶点着色器:将顶点沿法线方向外扩(注意转换到世界空间或视图空间,但通常在视图空间做外扩效果更均匀)。我们选择在视图空间做。
- 片元着色器:输出固定的描边颜色(包含透明度)。
物体Pass:
- 正常渲染物体。
但是,如果物体本身是半透明的,那么描边应该也是半透明的?我们可以通过调整描边颜色的alpha值来实现。
另外,我们还需要考虑双面渲染。因为描边Pass通常需要绘制背面(外扩后,原来的背面变成了描边的外面),而物体Pass绘制正面。所以,在描边Pass中,我们设置Cull Front(剔除正面,即渲染背面),在物体Pass中,设置Cull Back(剔除背面,即渲染正面)。这样避免描边和物体内部重叠。
步骤:
1. 定义属性:
_MainTex ("Main Texture", 2D) = "white" {}
_MainColor ("Main Color", Color) = (1,1,1,1)
_OutlineColor ("Outline Color", Color) = (0,0,0,1) // 默认黑色,不透明
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.01
// 注意:_OutlineWidth的范围可以根据需要调整
2. 定义SubShader,标签设为"Queue"="Transparent",因为我们可能支持透明。也可以让用户通过属性设置队列。
3. 第一个Pass(描边Pass):
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Cull Front // 剔除正面,渲染背面(这样外扩的背面就会形成描边)
ZWrite Off // 关闭深度写入,避免描边写入深度后影响后续物体
ZTest Always // 总是通过深度测试,确保描边总是可见(但可能会绘制在其他物体前面)
Blend SrcAlpha OneMinusSrcAlpha // 使用标准混合模式
顶点着色器:将顶点转换到视图空间,然后沿视图空间的法线方向外扩,再转换到裁剪空间。
片元着色器:返回_OutlineColor。
4. 第二个Pass(物体Pass):
Tags { "Queue"="Transparent" }
Cull Back
ZWrite On
ZTest LEqual
Blend SrcAlpha OneMinusSrcAlpha
正常渲染物体。
顶点着色器(描边Pass)的详细步骤:
- 将顶点位置转换到视图空间:float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
- 将法线转换到视图空间:float3 viewNormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
- 归一化视图空间法线:viewNormal = normalize(viewNormal);
- 在视图空间中将顶点沿法线方向外扩:viewPos.xyz += viewNormal * _OutlineWidth;
- 将视图空间位置转换到裁剪空间:o.pos = mul(UNITY_MATRIX_P, viewPos);
物体Pass的顶点着色器就是正常的顶点变换。
但是,视图空间转换在Unity中可以使用UnityObjectToViewPos函数。
另外,外扩的宽度_OutlineWidth在视图空间中是固定的,所以当物体距离相机很远时,描边可能会变得很细。我们可以通过将外扩宽度乘以一个与距离相关的因子来保持屏幕上的宽度一致,但这会增加复杂度。这里我们先不处理。
考虑到性能,我们也可以在世界空间做外扩,但视图空间可以保证描边在屏幕上的宽度不会因为模型旋转而变化。
现在,我们编写Shader代码。
注意:由于我们支持透明度,所以混合模式使用Blend SrcAlpha OneMinusSrcAlpha。
另外,如果用户不需要整个物体透明,而只需要描边透明,那么我们可以分别控制。但我们的属性中,_OutlineColor包含alpha,所以可以单独调整描边的透明度。
下面给出完整的Shader代码:</think>### Unity 高亮描边 Shader(支持透明度调整)
以下是一个支持透明度调整的高亮描边 Shader,基于法线外扩技术实现,适用于 Unity URP 渲染管线。此 Shader 包含描边宽度、颜色、强度和透明度控制参数。
```hlsl
Shader "Custom/OutlineWithAlpha"
{
Properties
{
_MainTex ("Main Texture", 2D) = "white" {}
_Color ("Main Color", Color) = (1,1,1,1)
_OutlineColor ("Outline Color", Color) = (1,0.5,0,1) // 默认橙色高亮
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.02
_OutlineAlpha ("Outline Alpha", Range(0, 1)) = 1.0 // 透明度控制
_OutlineIntensity ("Outline Intensity", Range(0, 5)) = 1.0
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
// 描边Pass (先渲染)
Pass
{
Name "OUTLINE"
Cull Front
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
};
CBUFFER_START(UnityPerMaterial)
float4 _OutlineColor;
float _OutlineWidth;
float _OutlineAlpha;
float _OutlineIntensity;
CBUFFER_END
Varyings vert(Attributes input)
{
Varyings output;
// 顶点法线方向外扩
float3 normalVS = mul((float3x3)UNITY_MATRIX_IT_MV, input.normalOS);
float2 normalCS = TransformViewToProjection(normalVS.xy);
// 计算外扩位置
float4 positionCS = TransformObjectToHClip(input.positionOS.xyz);
positionCS.xy += normalize(normalCS) * _OutlineWidth * positionCS.w;
output.positionCS = positionCS;
return output;
}
half4 frag(Varyings input) : SV_Target
{
// 应用透明度和强度
half4 col = _OutlineColor;
col.a *= _OutlineAlpha; // 透明度控制
col.rgb *= _OutlineIntensity; // 强度控制
return col;
}
ENDHLSL
}
// 主物体Pass (后渲染)
Pass
{
Name "MAIN"
Cull Back
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
CBUFFER_START(UnityPerMaterial)
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
CBUFFER_END
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = TRANSFORM_TEX(input.uv, _MainTex);
return output;
}
half4 frag(Varyings input) : SV_Target
{
half4 col = tex2D(_MainTex, input.uv) * _Color;
return col;
}
ENDHLSL
}
}
}
```
### 关键功能说明
1. **透明度控制**:
- `_OutlineAlpha` 参数 (0-1范围) 控制描边透明度
- 在片元着色器中使用:`col.a *= _OutlineAlpha`
- 默认值1.0为完全不透明,0.0为完全透明
2. **高亮描边参数**:
```hlsl
_OutlineColor ("Outline Color", Color) = (1,0.5,0,1) // 默认橙色高亮
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.02
_OutlineIntensity ("Outline Intensity", Range(0, 5)) = 1.0
```
- 颜色:RGBA格式,支持透明度通道
- 宽度:屏幕空间描边粗细
- 强度:控制发光亮度
3. **渲染设置**:
```hlsl
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha // 标准透明混合
ZWrite Off // 描边Pass关闭深度写入
```
确保正确处理透明物体排序和混合[^1]
### 使用步骤
1. 创建新材质,选择此 Shader
2. 调整参数:
- 减小 `_OutlineAlpha` 使描边半透明
- 增加 `_OutlineIntensity` 增强发光效果
- 修改 `_OutlineColor` 改变描边色调
3. 应用到需要描边的模型
4. 如需全透明物体,同时调整主材质的 `_Color` 透明度
### 性能优化建议
1. 使用 `Cull Front` 减少50%描边渲染面数
2. 在移动端使用更简化的版本(移除非必要计算)
3. 控制 `_OutlineWidth` 避免过度外扩造成视觉失真
4. 对静态物体使用烘焙光照减少实时计算[^1]
> **技术说明**:此 Shader 使用视图空间法线外扩技术,相比屏幕后处理方案:
> - ✅ 优点:物体级控制,支持透明效果
> - ❌ 限制:对复杂拓扑结构可能出现不均匀描边
阅读全文
相关推荐



















