【Unity Shader】带描边的半透明材质处理(头发为例)

这篇博客主要介绍了如何使用Unity Shader为半透明材质,特别是头发,添加描边效果。作者通过3个Pass来处理,分别是开启深度写入处理AlphaTest、处理半透明物体及主体、剔除正面实现描边。文章还提到了利用顶点色控制描边的最新方法,并提供了全部代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近做头发shader的时候做了这么一个简单测试,用的模型是以前制作的一个角色头部,在这里用来记录一下作为学习的总结。

基本思路就是利用3个Pass处理带描边的半透明材质

看下最终的测试截图(头发的材质不在本次讨论范围,有机会单独做一个总结):



关于Blend部分也测试下截图保留:


1.第一个Pass开启深度写入,处理AlphaTest,但不输出颜色
//第一个Pass,开启深度写入,不输出颜色,处理AlphaTest部分
    Pass{
    // 仅仅是把模型的深度信息写入深度缓冲中从而剔除模型中被自身遮挡的片元
    ZWrite On
    // 用于设置颜色通道的写掩码(Wirte Mask)ColorMask RGB|A|0|(R/G/B/A组合)
    // 当为0时意味着该Pass不写入任何颜色通道,也就不会输出任何颜色
    //也可以不用,这样就能刻意控制AlphaTest导致的发丝边缘的颜色
    ColorMask 0
    CGPROGRAM

    #pragma vertex vert  
    #pragma fragment frag  
    #include "Lighting.cginc"  

    sampler2D _MainTex;
    float4 _MainTex_ST;
    fixed _AlphaTest;

    struct a2v {
    float4 vertex : POSITION;
    float4 texcoord : TEXCOORD0;
    };

    struct v2f {
    float4 pos : SV_POSITION;
    float2 uv : TEXCOORD2;
    };

    v2f vert(a2v v) {
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    return o;
    }
    fixed4 frag(v2f i) : SV_Target{
    fixed4 texColor = tex2D(_MainTex, i.uv);
    //AlphaTest
    clip(texColor.a - _AlphaTest);//clip函数,但参数为负数则舍弃该片元输出
    return fixed4(0,0,0,1);
    }
    ENDCG
    }
2.第二个Pass关闭深度写入,处理半透明物体以及主体部分
//第二个Pass,关闭深度写入,处理AlphaBlend半透明,处理光照等部分
    Pass{
    // 向前渲染路径的方式
    Tags{ "LightMode" = "ForwardBase" }

    Cull Off //关闭剔除,让头发双面显示
    ZWrite Off //关闭深度写入  
    //透明度混合需要关闭深度写入    
    //Orgb = SrcAlpha * Srgb + OneMinusSrcAlpha * Drgb
    //Oa = SrcAlpha * Sa + OneMinusSrcAlpha * Da
    //将本Shader计算出的颜色值(源颜色值) * 源Alpha值 + 目标颜色值(可以理解为背景色) * (1-源Alpha值),从而让源物
### 实现Unity半透明描边效果 在Unity中创建具有半透明特性的描边效果,主要依赖于对Shader的深入理解和灵活运用。为了达到这一目标,通常会采用Surface Shader或自定义Vertex and Fragment (Vert/Frag) Shaders来实现特定需求的效果。 对于半透明描边而言,在Shader内部设置合适的混合模式至关重要。具体来说,`Blend SrcAlpha OneMinusSrcAlpha`指令被广泛应用于此类场景下[^2]。这使得渲染对象能够以基于源颜色alpha通道的方式与背景图像相融合,从而呈现出自然过渡的半透明视觉效果。 下面是一个简单的示代码片段展示如何构建这样的Shader: ```csharp Shader "Custom/TranslucentOutline" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Color ("Main Color", Color) = (1,1,1,0.5) _OutlineColor ("Outline Color", Color) = (0,0,0,1) _OutlineWidth ("Outline Width", Range(0.0, 0.1)) = .05 } SubShader { Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"} Pass { Name "OUTLINE" Cull Front Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : SV_POSITION; float4 color : COLOR; }; uniform float _OutlineWidth; uniform float4 _OutlineColor; v2f vert(appdata_t v) { v2f o; // 计算顶点位置偏移量 float3 norm = normalize(mul((float3x3)unity_ObjectToWorld, v.normal)); float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz); float d = dot(norm, viewDir); o.pos = UnityObjectToClipPos(v.vertex + v.normal * (_OutlineWidth / abs(d))); o.color = _OutlineColor; return o; } half4 frag(v2f i) :COLOR { return i.color; } ENDCG } GrabPass{ "_BackgroundTexture"} Pass { Name "BASE" ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag sampler2D _MainTex; fixed4 _Color; struct data { float4 vertex : POSITION; float2 uv_MainTex : TEXCOORD0; }; data vert(data v){ v.vertex = UnityObjectToClipPos(v.vertex); return v; } half4 frag(data IN) : COLOR { half4 col = tex2D(_MainTex, IN.uv_MainTex) *_Color; clip(col.a - 0.1); // 剔除完全明像素 return col; } ENDCG } } } ``` 这段代码实现了两个重要功能:首先是通过调整顶点法线方向并乘以一定宽度参数 `_OutlineWidth` 来生成向外扩展的轮廓;其次是利用 `GrabPass` 技术捕捉当前屏幕内容作为背景纹理,并在此基础上绘制主体模型,确保两者之间存在适当层次关系的同时也支持了半透明属性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值