Unity 3D模型做半透明剪影效果

17 篇文章 9 订阅
16 篇文章 1 订阅

抓手

项目组需要一个类似如下的半透明剪影效果,不过我们是3D模型,那么就需要一些特殊的做法。

最终通过使用Stencil Buffer解决了。

详解

一、刚开始的的自以为是

刚做这个需求之前,以为很容易做,不就是在frag shader里return一个半透明的黑色颜色值吗?

然后Tags改成透明 

Tags { "RenderType"="Transparent" "Queue" = "Transparent" }

混合模式为

 Blend SrcAlpha OneMinusSrcAlpha

Zwrite Off

不就完了吗?

结果说明我真是想得太简单。得到了如下结果:

衣服和身体,重叠了,因为 Blend SrcAlpha OneMinusSrcAlpha的混合计算方式如下:

最终颜色 = shader计算的颜色值*alpha值+(1-alpha值)*屏幕现有颜色值

那么模型身体的像素点渲染过后,覆盖在身体前的衣服再渲染一遍,混合的颜色就成上面那样了。

那这个方案不可行,不是一个严格的剪影。

二、具体的实现办法

有两个办法可以解决上面的问题,

1是使用深度写入:

        Zwrite On
        ZTest Less
        offset -10000000, 0

offset r,m 的r值越小,就只渲染离摄像机越近的像素。

但是这样会导致它会渲染在所有物体之前,会穿UI。这个方案有瑕疵。

 2是使用Stencil Buffer

        Stencil
            {
                Ref 0
                Comp Equal
                Pass Invert
            }

这里的Ref值是0,如果buffer里的值也是0的话,就通过stencil test,如果通过stencil test和depth test,

这里写入的模版值是用的Invert状态,也就是255,并渲染该像素。

然后下个像素判断当前buffer值不是0的话,则不通过stencil test,则不会渲染。这样就会得到正确的剪影效果。

这个方案比较完美,既不会渲染到最前面,而且还整得跟纸片一样。

全部的代码如下(以下代码只能在URP管线下使用): 

Shader "Custom/CharacterShadow"
{
Properties
{        
        _Color ("主颜色", Color) = (0,0,0,0.6)
}
SubShader
{
    Tags { "RenderType"="Transparent" "Queue" = "Transparent+100" }
    LOD 200
     Pass
        {
        Blend SrcAlpha OneMinusSrcAlpha
        Zwrite Off
        //ZTest Less
        //offset -10000000, 0

        Stencil
            {
                Ref 0
                Comp Equal
                Pass Invert
            }
        Tags
        {
            "LightMode" = "UniversalForward"
        }
 
        HLSLPROGRAM    
            #pragma vertex LitPassVertex
            #pragma fragment LitPassFragment
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
 
            struct Attributes
            {
            float4 positionOS : POSITION;
            };
     
            struct Varyings
            {
                float4 pos : SV_POSITION;
            };

            CBUFFER_START(UnityPerMaterial)
            half4 _Color;
            CBUFFER_END

            Varyings LitPassVertex (Attributes v)
            {
                Varyings o;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(v.positionOS.xyz);
                o.pos = vertexInput.positionCS;
                
                return o;
            }
 
            half4 LitPassFragment (Varyings i) : SV_Target
            {
                return _Color;
            }
 
        ENDHLSL
    }
}
}

最终的效果,完美!

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值